My team are doing with 2 teams: server team and client team. We at server team will provide APIs for the client team to call. The APIs have many version, so that we need to match the server build and the respective client build - for example, the old client will refuse to work if the server build number is much larger than its support version and requires an update.
Because of the above reason, we need to send back the build version of server to client. Currently we are doing this by adding a static field in a Config class. But I'm concerned with the fact that we must manually increase it everytime a new server is built - especially when we do daily build. This process is quite error-prone and not quite elegant.
In my search, I see many propose for using maven plugins to manage the build version. Though I highly appreciated the auto-process, it still doesn't let the server know the build number. Server application should be able to return its build version to client through an API call.
I have thought of write the number version somewhere (remote database, files on server).
Is there any way to make the building process automatically increase the build version, but the application itself can retrieve this number in running also?
We are using Maven build and having Jenkin as the integration build server.
I usually read the version from the MANIFEST.MF file that is packaged in the JAR by Maven.
By default it looks something like this:
Manifest-Version: 1.0
Built-By: user
Build-Jdk: 1.6.0_35
Created-By: Apache Maven 3.0.4
Archiver-Version: Plexus Archiver
Name: Artifact
Implementation-Build: 1.14-SNAPSHOT
Version: 1.14-SNAPSHOT
From this file I read the Version element and use that to for instance display the build version of the application (and all versions of the packaged jars in a WAR/EAR for instance).
Something like this code should work:
public static String getApplicationVersion() {
String version = null;
try {
final List<VersionsUtil.Version> moduleVersions = VersionsUtil.getModuleVersions(Thread.currentThread().getContextClassLoader());
for (VersionsUtil.Version moduleVersion : moduleVersions) {
if (moduleVersion.name.equals("<NAME OF ARTIFACT TO GET>")) {
version = moduleVersion.version;
break;
}
}
} catch (IOException e) {
// We'll return null...
}
return version;
}
public class VersionsUtil {
private static final Logger LOG = LoggerFactory.getLogger(VersionsUtil.class);
/**
* Returns a list of the module versions available for the given class loader.
*
* #param classLoader the class loader to return module versions for
* #return a list of module versions
* #throws IOException in case there's an error reading the manifest
*/
public static List<Version> getModuleVersions(final ClassLoader classLoader) throws IOException {
return processResources(classLoader.getResources("META-INF/MANIFEST.MF"));
}
private static List<Version> processResources(final Enumeration<URL> resources) throws IOException {
final List<Version> moduleVersions = new ArrayList();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
Version v = process(resource);
if (v != null) {
moduleVersions.add(v);
}
}
return moduleVersions;
}
private static Version process(final URL resource) {
try {
Properties p = readResource(resource);
return createVersion(p);
} catch (IOException e) {
LOG.warn("Failed to read resource: " + resource, e);
return null;
}
}
private static Version createVersion(final Properties p) {
Object name = p.get("Name");
if (name != null) {
return new Version((String) name, (String) p.get("Version"));
}
return null;
}
private static Properties readResource(final URL resource) throws IOException {
LOG.trace("Reading resource: " + resource);
InputStream is = resource.openStream();
Properties p = new Properties();
p.load(is);
is.close();
return p;
}
public static final class Version {
String name;
String version;
private Version(final String name, final String version) {
this.name = name;
this.version = version;
}
}
}
Updated:
If you want Jenkins buildnumber in the MANIFEST.MF you can configure your POM.XML with something like:
...
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<archive>
<manifestSections>
<manifestSection>
<name>${project.name} (${project.artifactId})</name>
<manifestEntries>
<Version>${project.version}${build.number}</Version>
</manifestEntries>
</manifestSection>
</manifestSections>
</archive>
</configuration>
</plugin>
...
<properties>
<build.number />
</properties>
...
If you're interested in tagging the WAR/EAR files instead, you have to add the manifest configurations accordingly.
Then in your Jenkins job configuration, simply pass the BUILD_NUMBER parameter to the maven process like this: -Dbuild.number=$BUILD_NUMBER.
Related
I'm developing a custom authentication plugin for OAM(Oracle Access Manager) in Java language using JDeveloper IDE.
i'm parsing a URL and i get the variables i want from a JSONObject correctly on a Main.class file without triggering any kind of Exception
This leads me to the assumption that the whole parsing code is correct which means the readJsonFromUrl function does it job.
Let me mention what my PhillPlugin.class includes
public ExecutionStatus process(AuthenticationContext context) ,
triggered when the Plug-In is to run.
public void getDataGenerate(String Url), called inside process function to created the JSONObject from URL
public static JSONObject readJsonFromUrl(String url) called inside getDataGenerate function
private static String readAll(Reader rd) used for parsing inside readJsonFromUrl
Now i upload the Plug-In to the server, i run it and get the following in it's Logs
java.lang.NoClassDefFoundError: org/json/JSONObject
at phillplugin.PhillPlugin.readJsonFromUrl(PhillPlugin.java:184)
at phillplugin.PhillPlugin.getDataGenerate(PhillPlugin.java:132)
at phillplugin.PhillPlugin.process(PhillPlugin.java:63)
What is needed in order to create the Plug-In:
PhillPlugin.class
PhillPlugin.xml
MANIFEST.MF
I'm mentioning the above because i have to include somewhere in these files the org.json path. ( it already exists as an import in PhillPlugin.class and Main.class )
The org.json.jar is included in Project's Libraries as well as all the .jars in order to build the Plug-In
MANIFEST.MF
Manifest-Version: 1.0
Bundle-Version: 10
Bundle-Name: PhillPlugin
Bundle-Activator: phillplugin.PhillPlugin
Bundle-ManifestVersion: 2
Import-Package: org.osgi.framework;version="1.3.0",oracle.security.am.plugin,oracle.security.am.plugin.authn,oracle.security.am.plugin.impl,oracle.security.am.plugin.api,oracle.security.am.common.utilities.principal,oracle.security.idm,javax.security.auth
Bundle-SymbolicName: PhillPlugin
CLASSPATH: felix.jar, identitystore.jar, oam-plugin.jar, utilities.jar, org.json.jar
Sample of the PhillPlugin.Class
I'm not supposed to include the URL for security purposes. (Trust me it's Valid)
public void getDataGenerate(String Url) {
System.out.println("----- Reading Json Object -----");
JSONObject json;
try {
json = readJsonFromUrl(Url);
System.out.println("The Json Object: "+json.toString());
otp=Integer.parseInt((String) json.get("otp"));
System.out.println("The User is:"+user+"\n"+"His OTP is: "+otp);
} catch (Exception e) {
System.out.println("Exception : "+e.toString());
}
public static JSONObject readJsonFromUrl(String url) throws IOException,JSONException {
System.out.println("Opening Stream");
InputStream is = new URL(url).openStream();
System.out.println("Stream opened");
try {
System.out.println("----------\n\n\nUrl to Parse: "+url+"\n\n\n");
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
System.out.println("\n\n\n"+"BufferedReader opened\n\n\n\n");
String jsonText =(String) readAll(rd);
System.out.println("\n\n\nJsonTEXT:"+jsonText+"\n\n\n");
JSONObject json=null;
System.out.println("\n\n Created Json Instance\n\n\n");
try{
System.out.println("inside try statement - initializing JSONObject with the text above \n\n\n");
//-------ERROR TRIGGERED HERE---------
json = new JSONObject(jsonText);
System.out.println("--------------------Object created-------------------");
}catch (Exception e) {
System.out.println("\n\n\n\n\nJSONOBJECT failed to be created: \n"+e);
}
System.out.println("\n\n\nJSON OBJECT"+json+"\n\n\n\n");
return json;
} finally {
is.close();
}
private static String readAll(Reader rd) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp);
}
return sb.toString();
}
PhillPlugin.xml
<Plugin type="Authentication">
<author>uid=Phill</author>
<email>phill#oracle.com</email>
<creationDate>12:47:00, 2019-07-11</creationDate>
<description>Phill-Plugin Prints Hello</description>
<configuration>
</configuration>
</Plugin>
This is the output on server Logs before crashing:
Stream opened
----------
Url to Parse: https://something
BufferedReader opened
JsonTEXT: it's correct
Created Json Instance
inside try statement - initializing JSONObject with the text above
I'm worrying too much about the MANIFEST.MF file because probably i'm
doing something wrong in there
Sorry for the long post, i will provide any extra information if needed, Thank you
When writing an Authenticaiton Plugin for OAM Server , all extra libraries should be mentioned in MANIFEST.MF as well as the external .jar files.
Furthermore , all .jar files should be deployed in the final plugin .jar as well as the external libraries
In my case i had to include org.json.jar at the exported PhillPlugin.jar as follows:
PhillPlugin.jar
as you can see both org.json.jar and it's libraries org are required
Manifest.MF
The last step is to mention in MANIFEST.MF all the extra classes that you are using in your plugin
In my case i had to include this in my Import-Package Attribute in order to be able to create a JSONObject instance
org.json;resolution:=optional,
org.json.JSONObject;resolution:=optional
If you would like to use a JSONArray you had to add this:
org.json.JSONArray;resolution:=optional
and so on.
Edit: The class-path should be mentioned as follows:
Bundle-ClassPath: org.json.jar, felix.jar, identity-provider.jar, oam-plugin.jar, utilities.jar
The CLASSPATH entry in the MANIFEST.MF is obviously wrong. Correct name is Class-Path see: https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html
Whole MANIFEST.MF documentation: https://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
I'm having trouble using tools.jar present in jdk1.8.0_121/lib/tools.jar.
My $JAVA_HOME is set to:
# echo $JAVA_HOME
/usr/local/java/jdk1.8.0_121
The path to tools.jar is :
# ls /usr/local/java/jdk1.8.0_121/lib/tools.jar
/usr/local/java/jdk1.8.0_121/lib/tools.jar
And I use the following java executable to run the code:
/usr/local/java/jdk1.8.0_161/bin/java
But, when I access the VirtualMachine class, it throws
Caused by: java.lang.ClassNotFoundException: com.sun.tools.attach.VirtualMachine
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_161]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_161]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338) ~[na:1.8.0_161]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_161]
... 72 common frames omitted
Can someone explain why Java is not able to find lib/tools.jar in its classpath & What can I do to correct this behaviour?
To run on my local machine, I've added the following dependency in my pom:
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
But, when I deploy it on the server, this jar is not packaged due to system scope & neither does it find the jar on the server's jdk path.
Isn't it supposed to find all the jdk jars automatically?
I've also tried to add env variable $JAVA_HOME in the class-path entry of jar's MANIFEST file as follows:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: pankajsinghal
Class-Path: $JAVA_HOME/lib/
Created-By: Apache Maven 3.5.4
Build-Jdk: 1.8.0_181
But, this is also not working. Also, I don't want to add this lib's jar in my code explicitly as it's a JDK lib and I guess the proper way to access this would be from the system's JDK path itself. So, looking for a solution in this direction itself.
Any help is really appreciated.
You can try it like this:
java -cp "/path/your.jar:/usr/local/java/jdk1.8.0_121/lib/tools.jar" your.MainClass
or Refer to the following:
The type "com.sun.tools.javac.util.Assert" is not accessible
Hopefully it helped you.
You have to add that jar in project properties. In eclipse, To Add this Jar to your build path Right click the Project > Build Path > Configure build path> Select Libraries tab > Click Add External Libraries > Select the Jar file.
you can directly add toos.jar to your current classLoader, but it just an idea.
File getJar = new File(folderLibsPath + File.separator + "tools.jar");
URLClassLoader classLoaderExt = (URLClassLoader) this.getClassLoader();
URL jarUrl = getJar.toURI().toURL();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoaderExt, jarUrl);
referenced from:How to load JAR files dynamically at Runtime?
and don't forget to load the attach.so (or attach.dll)
by System.load(absPath) or System.loadLibrary(dllName)
File attachedDLL = new File(folderLibFilePath);
if (attachedDLL.exists()) {
System.load(attachedDLL.getAbsolutePath());
}
I think we had got the same issue, and this code works for my case.
Also, there is another way to add tools.jar into classpath, but actually they did the same thing:
public void onEnable() throws Exception {
URLClassPath ucp = (URLClassPath) Reflection.getPrivateField("ucp", this.getClassLoader().getParent()); // reflect the subClass of URLClassLoader
File getJar = new File(folderLibsPath + File.separator + "tools.jar");
URL jarUrl = getJar.toURI().toURL();
ucp.addURL(jarUrl); // or just change its "URLs" field by put your jarURL in its Stack
}
But it should be mention that, this way the Java will use the AppClassLoader(SystemClassLoader) to load the tools.jar (also the invoker - your application will). This may have a bad effect on your original class initialization if you use CustomClassLoader. (because depending on the Java Parent Delegation Model, the superClassLoader cannot know which class load by its subClassLoader).
So if you are developing a plugin under a customClassLoader (the subclass of system classloader), the classpath in AppClassLoader should be removed (which means let custom PluginClassLoader to load it, or not its super one) after your VM was detached.
here I used reflection to accomplished.
public class Main {
public void onEnable() throws Exception {
/** load attach.dll */
System.loadLibrary("attach");
/** load tools.jar */
URLClassPath ucp = (URLClassPath) Reflection.getPrivateField("ucp", this.getClassLoader().getParent());
File getJar = new File(folderLibsPath + File.separator + "tools.jar");
URL jarUrl = getJar.toURI().toURL();
ucp.addURL(jarUrl);
/** attach, load, detach VM */
VirtualMachine vm;
vm = VirtualMachine.attach(this.getPid());
// if the current jar itself is the agent
vm.loadAgent(new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getAbsolutePath());
vm.detach();
/** change the classLoader back to your custom */
changeClassLoaderBack();
/** unload native DLL Lib */
unloadNativeLibs(); // or you can add a condition to unload attach.dll only
}
public void changeClassLoaderBack() {
URLClassPath ucp = (URLClassPath) Reflection.getPrivateField("ucp", this.getClassLoader().getParent());
/** reset field path */
List<?> path = (ArrayList<?>) Reflection.getPrivateField("path", ucp);
List<URL> newPath = new ArrayList<>();
path.forEach((v) -> {
if(!((URL)v).getPath().contains("toos.jar") && !((URL)v).getPath().contains(this.getPlugin().getName())) {
newPath.add(((URL)v));
}
});
Reflection.setPrivateField("path", ucp, newPath);
/** reset field URLs */
Reflection.setPrivateField("urls", ucp, new Stack<URL>());
/** reset fields loader and LMAP */
List<Object> newLoader = new ArrayList<>();
Map<Object, Object> newLMAP = new HashMap<>();
((HashMap<?,?>)Reflection.getPrivateField("lmap", ucp)).forEach((k,v) -> {
if (!((String)k).contains("tools.jar") && !((String)k).contains(this.getPlugin().getName())) {
newLMAP.put(k, v);
newLoader.add(v);
};
});
Reflection.setPrivateField("lmap", ucp, newLMAP);
Reflection.setPrivateField("loaders", ucp, newLoader);
}
private String getPid() {
RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
String pid = bean.getName();
if (pid.contains("#")) {
pid = pid.substring(0, pid.indexOf("#"));
}
return pid;
}
private void unloadNativeLibs(ClassLoader unloadDLLfromWhichLoader) {
try {
ClassLoader classLoader = unloadDLLfromWhichLoader;
Field field = ClassLoader.class.getDeclaredField("nativeLibraries");
field.setAccessible(true);
Vector<?> libs = (Vector<?>) field.get(classLoader);
Iterator<?> it = libs.iterator();
Object o;
while (it.hasNext()) {
o = it.next();
Method finalize = o.getClass().getDeclaredMethod("finalize", new Class[0]);
finalize.setAccessible(true);
finalize.invoke(o, new Object[0]);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Reflection {
public static Object getPrivateField(String fieldName, Object object) {
Field field;
Object o = null;
try {
field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
o = field.get(object);
}
catch (NoSuchFieldException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
return o;
}
public static void setPrivateField(String fieldName, Object object, Object newField) {
Field field;
try {
field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, newField);
}
catch (NoSuchFieldException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
hope it can help you at some points
My PC in running under Windows7 64 bit, and I have an utility (.exe, very legacy [~WinXP age], no sources available) that I'd like to invoke from java code deployed into Jetty.
If I launch utility from console I get no errors. If I launch utility via simple java wrapper:
import java.util.*;
import java.io.*;
public class Wrapper {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("java.version"));
Runtime.getRuntime().exec("util.exe -opt1 -opt2");
}
}
I get no errors as well.
But in case I invoke this code (a bit more complex than Runtime.getRuntime().exec("util.exe") because I need to calculate absolute path to the binary file) from inside WAR I get IOException with following message:
CreateProcess error=216, This version of %1 is not compatible with the version of Windows you're running. Check your computer's system information to see whether you need a x86 (32-bit) or x64 (64-bit) version of the program, and then contact the software publisher
I've tried to launch jetty with -d32 option, tried to put different versions of java (both JRE/JDK, both 6/7, both 32/64 bit) into JAVA_HOME and PATH — and haven't succeed.
Did anyone face similar issues? Is it possible to resolve them?
[UPDATED]
I've attached some server-code.
CommandLine & FileUtils are part of Apache Commons. ApplicationContext relates to Spring Framework.
public class ImageLoader implements ApplicationContextAware {
private final static String UTIL_EXECUTABLE = "util.exe";
private final static String TEMP_FILE_PREFIX = "tmpFilePrefix";
private ApplicationContext applicationContext;
private File binaryPath;
#PostConstruct
public void init() throws Exception {
if (applicationContext instanceof WebApplicationContext) {
Resource binaryRoot = applicationContext.getResource(
"WEB-INF/classes/executable");
this.binaryPath = binaryRoot.getFile();
}
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* Download db image from device.
*/
public byte[] downloadImage(Device device) throws LoaderException {
try {
File file = downloadWindows(device);
return FileUtils.readFileToByteArray(file);
} catch (Exception ex) {
throw new LoaderException("Error downloading file: " + ex.getMessage(), ex);
}
}
private File downloadWindows(final Device device) throws Exception {
File tmpFile = File.createTempFile(TEMP_FILE_PREFIX, null);
CommandLine command = generateCommand(ActionType.download, tmpFile, device.getTargetIP(), "user", "pass");
Runtime.getRuntime().exec(command.toString());
return tmpFile;
}
protected CommandLine generateCommand(ActionType actionType, File file, String targetIP, String userName, String userPassword) throws IOException {
String bin = this.binaryPath.getPath() + "\\" + UTIL_EXECUTABLE;
// safe to use \\ because code only runs if WAR deployed under Windows
CommandLine commandLine = new CommandLine(bin.replace("\\", "\\\\"));
commandLine.addArgument(actionType.name());
commandLine.addArgument(file.getAbsolutePath().replace("\\", "\\\\"));
commandLine.addArgument(targetIP);
commandLine.addArgument(userName);
commandLine.addArgument(userPassword);
return commandLine;
}
}
enum ActionType {
download,
upload
}
Shame on me and my inattention. The problem actually was "elsewhere". The WAR was built by maven and the executable was processed like any other resource, so checksum was different in compare to original file. I excluded exe-files from filteing (in pom.xml) and it began to work correct.
Along the lines of "This tape will self-destruct in five seconds. Good luck, Jim"...
Would it be possible for an application to delete itself (or it's executable wrapper form) once a preset time of use or other condition has been reached?
Alternatively, what other approaches could be used to make the application useless?
The aim here is to have a beta expire, inviting users to get a more up-to-date version.
It is possible. To get around the lock on the JAR file, your application may need to spawn a background process that waits until the JVM has exited before deleting stuff.
However, this isn't bomb-proof. Someone could install the application and then make the installed files and directories read-only so that your application can't delete itself. The user (or their administrator) via the OS'es access control system has the final say on what files are created and deleted.
If you control where testers download your application, you could use an automated build system (e.g. Jenkins) that you could create a new beta versions every night that has a hard-coded expiry date:
private static final Date EXPIRY_DATE = <90 days in the future from build date>;
the above date is automatically inserted by the build process
if (EXPIRY_DATE.before(new Date()) {
System.out.println("Get a new beta version, please");
System.exit(1);
}
Mix that with signed and sealed jars, to put obstacles in the way of decompiling the bytecode and providing an alternative implementation that doesn't include that code, you can hand out a time-expiring beta of the code.
The automated build system could be configured to automatically upload the beta version to the server hosting the download version.
Since Windows locks the JAR file while it is running, you cannot delete it from your own Java code hence you need a Batch file:
private static void selfDestructWindowsJARFile() throws Exception
{
String resourceName = "self-destruct.bat";
File scriptFile = File.createTempFile(FilenameUtils.getBaseName(resourceName), "." + FilenameUtils.getExtension(resourceName));
try (FileWriter fileWriter = new FileWriter(scriptFile);
PrintWriter printWriter = new PrintWriter(fileWriter))
{
printWriter.println("taskkill /F /IM \"java.exe\"");
printWriter.println("DEL /F \"" + ProgramDirectoryUtilities.getCurrentJARFilePath() + "\"");
printWriter.println("start /b \"\" cmd /c del \"%~f0\"&exit /b");
}
Desktop.getDesktop().open(scriptFile);
}
public static void selfDestructJARFile() throws Exception
{
if (SystemUtils.IS_OS_WINDOWS)
{
selfDestructWindowsJARFile();
} else
{
// Unix does not lock the JAR file so we can just delete it
File directoryFilePath = ProgramDirectoryUtilities.getCurrentJARFilePath();
Files.delete(directoryFilePath.toPath());
}
System.exit(0);
}
ProgramDirectoryUtilities class:
public class ProgramDirectoryUtilities
{
private static String getJarName()
{
return new File(ProgramDirectoryUtilities.class.getProtectionDomain()
.getCodeSource()
.getLocation()
.getPath())
.getName();
}
public static boolean isRunningFromJAR()
{
String jarName = getJarName();
return jarName.contains(".jar");
}
public static String getProgramDirectory()
{
if (isRunningFromJAR())
{
return getCurrentJARDirectory();
} else
{
return getCurrentProjectDirectory();
}
}
private static String getCurrentProjectDirectory()
{
return new File("").getAbsolutePath();
}
public static String getCurrentJARDirectory()
{
try
{
return getCurrentJARFilePath().getParent();
} catch (URISyntaxException exception)
{
exception.printStackTrace();
}
throw new IllegalStateException("Unexpected null JAR path");
}
public static File getCurrentJARFilePath() throws URISyntaxException
{
return new File(ProgramDirectoryUtilities.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
}
}
Solution inspired by this question.
Here is a better method for Windows:
private static void selfDestructWindowsJARFile() throws Exception
{
String currentJARFilePath = ProgramDirectoryUtilities.getCurrentJARFilePath().toString();
Runtime runtime = Runtime.getRuntime();
runtime.exec("cmd /c ping localhost -n 2 > nul && del \"" + currentJARFilePath + "\"");
}
Here is the original answer.
it is pretty possible i guess. maybe you can delete the jar like this and make sure the application vanishes given that you have the rights.
File jar = new File(".\\app.jar");
jar.deleteOnExit();
System.exit(0);
also using something like Nullsoft Scriptable Install System which enables you to write your own installed/uninstaller should help.
There's a lot of discussion about Ant and Eclipse, but no previously answered seems to help me.
Here's the deal: I am trying to build a Java program that compiles successfully with Ant from the command-line. (To confuse matters further, the program I am attempting to compile is Ant itself.)
What I really want to do is to bring this project into Eclipse and have it compile in Eclipse such that the type bindings and variable bindings (nomenclature from Eclipse JDT) are correctly resolved. I need this because I need to run a static analysis on the code that is built on top of Eclipse JDT. The normal way I bring a Java project into Eclipse so that Eclipse will build it and resolve all the bindings is to just import the source directories into a Java project, and then tell it to use the src/main/ directory as a "source directory."
Unfortunately, doing that with Ant causes the build to fail with numerous compile errors. It seems to me that the Ant build file is setting up the class path and build path correctly (possibly by excluding certain source files) and Eclipse does not have this information.
Is there any way to take the class path & build path information embedded in an Ant build file, and given that information to Eclipse to put in its .project and .classpath files? I've tried, creating a new project from an existing build file (an option in the File menu) but this does not help. The project still has the same compile errors.
Thanks,
Nels
I've never found a really clean way to do it, but one "hackish" way to do it is to manipulate the .classpath file eclipse uses (this contains the build path).
So the .classpath is going to have stuff in it like this:
<classpathentry kind="lib" path="C:/jboss-4.2.3.GA/client/jboss-system-client.jar"/>
So you could, for example, write some sort of batch script, etc. which would read your ant file dependencies and put them into the eclipse .classpath file (in the proper format, of course).
But personally, I never fool with such things. What I do is just put all the jars my project needs in one folder, and then in my ant file I have a path set up like this:
<path id="all_libs">
<fileset dir="test_reflib">
<include name="**/*.jar"/>
</fileset>
</path>
test_reflib just needs to be defined to wherever this folder is that contains all the jars.
Then, on the eclipse side you can just do a "Add jars" and navigate to this same folder and just pick all the jars. What's even cooler is that any time you drop new jars into this folder, just click at the root level in the eclipse project and do "Refresh", and then edit the build path and click add jar again and it will only show you the jars that you haven't already added to the build path yet (i.e. the new jar you just dropped into the folder).
This obviously doesn't work too well if you are sharing jars in a central place, but it works pretty well for smaller projects where you can just copy all the jars over to a centralized folder for the project.
I use the ivy to manage my ANT classpaths, I highly recommend learning how it works.
There is an eclipse plugin that will manage the eclipse classpath from the same ivy.xml file that ANT uses to define it's dependencies.
I wrote an Ant Task that generates an Eclipse .userlibraries file. You can import the generated file to create a user library in Eclipse. And then use this user library as part of your build path.
To use the task add this to your ant build file:
<target name="createEclipseUserLibraries"
description="Creates classpath and bootclasspatch that can be imported into Eclipse">
<taskdef name="createEclipseUserLibraries"
classname="com.forumsys.tools.CreateEclipseUserLibraries"
classpathref="yourclasspathref"/>
<createEclipseUserLibraries classpathref="classpathref" bootclasspathref="bootclasspathref"/>
</target>
Ant Task. It requires ant.jar to run and compile:
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Reference;
/**
* A custom tag to create a file the eclipse can import to setup a user libraries.
*
* Created: Mar 29, 2014 9:44:09 AM
*
* #author Javier S. López
* #version 1.0
*/
public class CreateEclipseUserLibraries extends Task {
public static final String UTF8_ENCODING = "UTF-8";
public static final String DEFAULT_BOOT_CLASSPATH_LIBRARY_NAME = "SYSTEM_LIBRARY";
public static final String DEFAULT_CLASSPATH_LIBRARY_NAME = "LIBRARY";
public static final String DEFAULT_DESTINATION = "Eclipse.userlibraries";
private static final String INDENT = " ";
private Path _classpath;
private Path _bootClasspath;
private String _bootClasspathLibraryName = DEFAULT_BOOT_CLASSPATH_LIBRARY_NAME;
private String _classpathLibraryName = DEFAULT_CLASSPATH_LIBRARY_NAME;
private String _destination = DEFAULT_DESTINATION;
public void setClasspath(final Path classpath) {
if (_classpath == null) {
_classpath = classpath;
} else {
_classpath.append(classpath);
}
}
public void setClasspathRef(final Reference reference) {
if (_classpath == null) {
final Project antProject = getProject();
_classpath = new Path(antProject);
}
_classpath.setRefid(reference);
}
public void setBootClasspath(final Path bootClasspath) {
if (_bootClasspath == null) {
_bootClasspath = bootClasspath;
} else {
_bootClasspath.append(bootClasspath);
}
}
public void setBootClasspathRef(final Reference reference) {
if (_bootClasspath == null) {
final Project antProject = getProject();
_bootClasspath = new Path(antProject);
}
_bootClasspath.setRefid(reference);
}
public void setClasspathLibraryName(final String name) {
if (!isEmpty(name)) {
_classpathLibraryName = name;
}
}
public void setBootClasspathLibraryName(final String name) {
if (!isEmpty(name)) {
_bootClasspathLibraryName = name;
}
}
public void setDestination(final String argDestination) {
if (!isEmpty(argDestination)) {
_destination = argDestination;
}
}
#Override
public void execute() throws BuildException {
if (_classpath == null) {
throw new BuildException("classpath or classpathref attribute must be set");
}
if (_bootClasspath == null) {
throw new BuildException("bootclasspath or bootclasspathref attribute must be set");
}
try {
createUserLibrariesFile();
} catch (final IOException e) {
throw new BuildException(e.getMessage(), e);
}
}
/**
* #throws IOException
*
*/
private void createUserLibrariesFile() throws IOException {
final StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<?final xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
stringBuilder.append("\n");
stringBuilder.append("<eclipse-userlibraries version=\"2\">").append("\n");
createBootClasspathLibrary(stringBuilder);
createClasspathLibrary(stringBuilder);
stringBuilder.append("</eclipse-userlibraries>");
final Project antProject = getProject();
final File baseDir = antProject.getBaseDir();
final File file = new File(baseDir, _destination);
if (file.exists()) {
file.delete();
}
final boolean append = false;
BufferedOutputStream bos = null;
try {
final FileOutputStream fos = new FileOutputStream(file, append);
bos = new BufferedOutputStream(fos);
bos.write(stringBuilder.toString().getBytes(UTF8_ENCODING));
bos.flush();
} finally {
if (bos != null) {
bos.close();
}
}
}
/**
* #param stringBuilder
*
*/
private void createBootClasspathLibrary(final StringBuilder stringBuilder) {
createLibrary(stringBuilder, _bootClasspathLibraryName, true, _bootClasspath);
}
/**
* #param stringBuilder
*/
private void createClasspathLibrary(final StringBuilder stringBuilder) {
createLibrary(stringBuilder, _classpathLibraryName, false, _classpath);
}
/**
* #param stringBuilder
* #param bootClasspathLibraryName
* #param b
* #param bootClasspath
*/
private void createLibrary(final StringBuilder stringBuilder, final String libraryName,
final boolean isSystemLibrary, final Path path) {
stringBuilder.append(INDENT).append("<library name=\"").append(libraryName);
stringBuilder.append("\" systemlibrary=\"").append(Boolean.toString(isSystemLibrary)).append("\">\n");
final String[] paths = path.list();
final Project antProject = getProject();
final File baseDir = antProject.getBaseDir();
final String baseDirName = baseDir.getName();
for (final String strPath : paths) {
final int index = strPath.indexOf(baseDirName);
//Only include the relative path
if (index != -1) {
stringBuilder.append(INDENT).append(INDENT);
stringBuilder.append("<archive path=\"").append(
strPath.substring(index - 1)).append("\"/>\n");
}
}
stringBuilder.append(INDENT).append("</library>\n");
}
public static final boolean isEmpty(final String str) {
return (str == null) || (str.length() == 0);
}
}
From the raw ant distribution, first run "ant -f fetch.xml" (or similar) to download a lot of needed dependencies. Add these to your Eclipse project and see if it helps.
We have generated Eclipse .classpath and .project files from Ant for a large project with centrally located jars (100+) (not counting src jars and javadocs). Similar to the build.xml linked from here with the obvious addition of the src and javadoc attributes.