I have 2 plugins A and B. In the MANIFEST.MF of the A I do have plugin B in a Require-Bundle section. But when I try to get B's resource from A like
ClassFromA.class.getClassLoader().getResource('resource_from_B')
I am getting null. If I put B's resourŅe (folder) to A's root everything works like a charm. Am I missing something?
NOTE: I read Lars Vogel's article
Bundle bundle = Platform.getBundle("de.vogella.example.readfile");
URL fileURL = bundle.getEntry("files/test.txt");
File file = null;
try {
file = new File(FileLocator.resolve(fileURL).toURI());
} catch (URISyntaxException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
^this solution works when I run my plugin from eclipse, but when I pack it to jar and try to install from the local update site I'm getting
java.lang.IllegalArgumentException: URI is not hierarchical
P.S. I have also read several relative questions on the StackOverflow but wasn't able to find the answer:
Java Jar file: use resource errors: URI is not hierarchical
Why is my URI not hierarchical?
SOLUTION:
Many thanks to #greg-449. So the correct code is:
Bundle bundle = Platform.getBundle("resource_from_some_plugin");
URL fileURL = bundle.getEntry("files/test.txt");
File file = null;
try {
URL resolvedFileURL = FileLocator.toFileURL(fileURL);
// We need to use the 3-arg constructor of URI in order to properly escape file system chars
URI resolvedURI = new URI(resolvedFileURL.getProtocol(), resolvedFileURL.getPath(), null);
File file = new File(resolvedURI);
} catch (URISyntaxException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
NOTE: also it's very important to use the 3-arg constructor of URI in order to properly escape file system chars.
Use
FileLocator.toFileURL(fileURL)
rather than FileLocator.resolve(fileURL) when you want to use the URL with File.
When the plugin is packed into a jar this will cause Eclipse to create an unpacked version in a temporary location so that the object can be accessed using File.
Why not use Bundle.getResource? That seems to be the OSGi way to access resources.
Your first attempt might work if you use a ClassFromB.class.getClassLoader instead of A.
Related
I need to find all the Java types (classe, interface, enum, annotation) in all projectes' source directories of workspace, given a name as String. For example, input "Test" would return all the Java types whose names start with "Test" defined in all the projects source directories. I tried to handle this with JDT's SearchEngine as follows
SearchPattern pattern = SearchPattern.createPattern("Test",
IJavaSearchConstants.TYPE, IJavaSearchConstants.DECLARATIONS,
SearchPattern.R_PREFIX_MATCH);
IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
SearchRequestor requestor = new SearchRequestor() {
public void acceptSearchMatch(SearchMatch match) {
System.out.println("Found: " + match.getElement());
}
};
SearchEngine searchEngine = new SearchEngine();
try {
searchEngine.search(pattern, new SearchParticipant[] { SearchEngine
.getDefaultSearchParticipant() }, scope, requestor,
null);
} catch (CoreException e) {
e.printStackTrace();
}
The code above returned some java types not in Eclipse workspace. For example:
Found: TestSimple (not open) [in TestSimple.class [in <default> [in /home/me/test]]]
TestSimple.java is a file created from command line in my home directory and it has nothing to do with Eclipse projects. (My Eclipse workspace is defined in /home/me/eclipse/workspace.) I am not sure why it is included in the search result? Is SearchEngine the best way to handle this scenario, given the fact that I just need the java type names, I don't need anything inside a class such as field, method or reference? Thanks
You probably want to build a more confined search scope, then, asking each IJavaProject for all of its package fragment roots (IJavaProject#getAllPackageFragmentRoots()) and including only those returning K_SOURCE from IPackageFragmentRoot#getKind() to avoid getting types from referenced libraries as well. A search on just names shouldn't do much more than hit the indexes that are already being stored. You can't just rely on filenames because it would miss inner classes entirely.
I am getting the following exception in my glassfish 4 application that uses log4j2:
SEVERE: ERROR StatusLogger Invalid URL C:/glassfish4/glassfish/domains/domain1/config/log4j2.xml java.net.MalformedURLException: Unknown protocol: c
I have the following section in my log4j2.xml:
<RollingFile name="RollingFile" fileName="C:/glassfish4/glassfish/domains/domain1/logs/ucsvc.log"
filePattern="C:/glassfish4/glassfish/domains/domain1/logs/$${date:yyyy-MM}/ucsvc-%d{MM-dd-yyyy}-%i.log">
I understand that if it's looking for a URL, then "C:/glassfish4/..." is not the correct format.
However, the rolling file part actually works: I see a log file and the rolled log files where I expect them.
If I change to a URL (e.g. file:///C/glassfish4/...) that doesn't work at all.
So should I ignore the exception? (everything seems to be working ok). Or can someone explain the correct format for this section of the configuration?
I have not yet fully determined why it is that the config file works for me as well as the OP, but, I can confirm that changing the path reference to a file:// url solves the problem (ie: gets rid of the error/warning/irritant).
In my IntelliJ Run/Debug configurations, for VM options, I have:
-Dlog4j.configurationFile=file://C:\dev\path\to\log4j2.xml
I can confirm that '\' are translated to '/' so, no worries there.
EDIT:
Okay, the whole thing works because they (the apache guys) try really hard to load the configuration and they do, in fact, load from the file as specified via the c:\... notation. They just throw up a rather misleading exception before continuing to try.
In ConfigurationFactory::getConfiguration:
**source = getInputFromURI(FileUtils.getCorrectedFilePathUri(config));**
} catch (Exception ex) {
// Ignore the error and try as a String.
}
if (source == null) {
final ClassLoader loader = this.getClass().getClassLoader();
**source = getInputFromString(config, loader);**
The first bolded line tries to load from a URL and fails, throwing the exception. The code then continues, pops into getInputFromString:
try {
final URL url = new URL(config);
return new ConfigurationSource(url.openStream(), FileUtils.fileFromURI(url.toURI()));
} catch (final Exception ex) {
final ConfigurationSource source = getInputFromResource(config, loader);
if (source == null) {
try {
**final File file = new File(config);
return new ConfigurationSource(new FileInputStream(file), file);**
Where it tries to load the config again, fails and falls into the catch, tries again, fails and finally succeeds on the bolded lines (dealing with a File).
Okay, the code lines I wanted in emphasize with bold are actually just wrapped in **; guess the site doesn't permit nested tags? Anyway, y'all get the meaning.
It's all a bit of a mess to read, but that's why it works even though you get that nasty-looking (and wholly misleading) exception.
Thanks Jon, i was searching all over.. this helped!
This is on Intellij 13, Tomcat 7.0.56
-Dlog4j.configurationFile=file://C:\Surendra\workspace\cmdb\resources\elasticityLogging.xml
The problem is not the contents of your log4j2.xml file.
The problem is that log4j2 cannot locate your log4j2.xml config file. If you look carefully at the error, the URL that is reported as invalid is C:/glassfish4/glassfish/domains/domain1/config/log4j2.xml: the config file.
I'm not sure why this is. Are you specifying the location of the config file via the system property -Dlog4j.configurationFile=path/to/log4j2.xml?
Still, if the application and logging works then perhaps there is no problem. Strange though. You can get more details about the log4j configuration by configuring <Configuration status="trace"> at the top of your log4j2.xml file. This will print log4j initialization details to the console.
I am having a view which extends CommonNavigator.
I am creating a custom project through a CustomProjectCreation wizard.
Only refresh as given below works, but it refreshes all the projects each time a new project is created which should be avoided,
CommonNavigator resNav;
try {
resNav = (CommonNavigator)activePage.findView("view id");
resNav.getCommonViewer().refresh();
//resNav.getCommonViewer().refresh(newProject); //doesn't work
} catch (PartInitException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ContentProvider looks as below
if(parentElement instanceof IWorkspaceRoot){
List customProjects = getCustomProjects();
return customProjects.toArray(new CustomProject[customProjects.size()]);
}
On Debug, getCommonViewer().refresh() calls the getChildren() method in the content provider.
getCommonViewer().refresh(newProject) doesn't make a call to ContentProvider
expandtolevel and setExpandedState aren't working...
How to achieve refresh in particular to the newly created project?
How to expand the created project?
Regards,
Aravind
Are you sure that the problem is in the common navigator? If you have created the artifacts inside of your new project by using non Eclipse resource access methods (that is normal Java file IO instead of IResource, IFile and related code), then the model just does not know about the new content. If this is the case, you would need yourProjectResource.refreshLocal() first.
Their Seems to be a problem when i attempt to run JAXB marshaller in a netbeans module. Originally I thought it was the node implimentation so i spent a couple of days reorganizing everything however I was still recieveing the odd error message
javax.xml.bind.JAXBException: ClassCastException: attempting to cast jar:file:/C:/Program%20Files/jmonkeyplatform/ide/modules/ext/jaxb/api/jaxb-api.jar!/javax/xml/bind/JAXBContext.class to jar:file:/C:/Program%20Files/Java/jdk1.6.0_21/jre/lib/rt.jar!/javax/xml/bind/JAXBContext.class. Please make sure that you are specifying the proper ClassLoader.
at javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:96)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:205)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:363)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:522)
at com.spectre.util.JAXBImporterExporter.write(JAXBImporterExporter.java:63)
I am not exactly sure what the issue is the importer/exporter seems to work in normal projects and the importer seems to work fine when parsing the file however the export seems to cause issues. The method I use to export is
public static <T> void write(T savable, Class<T> type,Object path) {
try {
JAXBContext jc = JAXBContext.newInstance(type);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
if(path instanceof File)
marshaller.marshal(savable, (File)path);
else if(path instanceof OutputStream){
marshaller.marshal(savable, (OutputStream)path);
}else throw new NoSuchMethodException("The Field Path must be of either type File or OutputStream");
} catch (NoSuchMethodException ex) {
Exceptions.printStackTrace(ex);
} catch (JAXBException ex) {
Exceptions.printStackTrace(ex);
}
}
any assistance is appreciated
An easy solution is to add module dependency on org.netbeans.modules.xml.jaxb.api module that is part of NetBeans. This will avoid clash between two versions JAXB classes (one from JDK and second from that module that is preferred in runtime).
I Found that if you instead change the initialization of the JAXBContext to JAXBContext.newInstane(String contextPath,ClassLoader loader) in which the class loader you recieve from the current class your in ie MyClass.class.getClassLoader(). Also instead of a schema you can use a jaxb.index which is just a text file list of the class names that you've augmented for use with jaxb that is inside their same directory. Their should be one for each directory though for me they where all in the same directory. and seperated in the same string in the constructor's context path param with :
HERE
I am trying to build a offline gwt app using HTML5 cache manifest and
local storage, but to do that, i need to build the manifest file
listing all the GWT generated files, right?
Can i do this during the compile process or is it better to do this in
a shell script?
This should be done using a Linker, so that your resources are automatically added to the manifest at compile time. I know there exists an HTML5 cache manifest linker, since the GWT team has mentioned it a few times, but I don't know where the source is.
The closest alternative (and probably a good starting point for writing an HTML5 linker) is the Gears offline linker. Gears' offline manifests are pretty similar to HTML5's, so it's probably a matter of changing a few lines to make it work.
There's also an informative video about using GWT linkers to have your app take advantage of HTML5 Web Workers.
I just had to do this other day at work. Like the previous answer says, you just need to add a linker. Here's an example of one that creates a manifest file for the Safari user agent based on a template file.
// Specify the LinkerOrder as Post... this does not replace the regular GWT linker and runs after it.
#LinkerOrder(LinkerOrder.Order.POST)
public class GwtAppCacheLinker extends AbstractLinker {
public String getDescription() {
return "to create an HTML5 application cache manifest JSP template.";
}
public ArtifactSet link(TreeLogger logger, LinkerContext context, ArtifactSet artifacts) throws UnableToCompleteException {
ArtifactSet newArtifacts = new ArtifactSet(artifacts);
// search through each of the compilation results to find the one for Safari. Then
// generate application cache for that file
for (CompilationResult compilationResult : artifacts.find(CompilationResult.class)) {
// Only emit the safari version
for (SelectionProperty property : context.getProperties()) {
if (property.getName().equals("user.agent")) {
String value = property.tryGetValue();
// we only care about the Safari user agent in this case
if (value != null && value.equals("safari")) {
newArtifacts.add(createCache(logger, context, compilationResult));
break;
}
}
}
}
return newArtifacts;
}
private SyntheticArtifact createCache(TreeLogger logger, LinkerContext context, CompilationResult result)
throws UnableToCompleteException {
try {
logger.log(TreeLogger.Type.INFO, "Using the Safari user agent for the manifest file.");
// load a template JSP file into a string. This contains all of the files that we want in our cache
// manifest and a placeholder for the GWT javascript file, which will replace with the actual file next
String manifest = IOUtils.toString(getClass().getResourceAsStream("cache.template.manifest"));
// replace the placeholder with the real file name
manifest = manifest.replace("$SAFARI_HTML_FILE_CHECKSUM$", result.getStrongName());
// return the Artifact named as the file we want to call it
return emitString(logger, manifest, "cache.manifest.");
} catch (IOException e) {
logger.log(TreeLogger.ERROR, "Couldn't read cache manifest template.", e);
throw new UnableToCompleteException();
}
}
}
Use the gwt2go library's GWT Application Manifest generator to do precisely that. That was easy. :)