Validating against a schema that lives inside a plugin - eclipse

Background:
I have a small problem with Eclipse. I'm working on a workbench plugin which has some classes that validate incoming XML data against a schema. The schema lives inside the plugin project in a "./schemas" folder.
Questions:
When I run the application, how can I read the schema without using a hardcoded path?
When the application is deployed the schema will need to live inside a plugin .jar. Will the solution from (1) be any different in this case?

You can use the FileLocator class from org.eclipse.core.runtime to get a URL to a resource in your bundle.
For example, something like
URL schema = FileLocator.find(myBundle, new Path("/schemas/data.xsd"), null);
You can get your Bundle object from the BundleContext passed into your Activator (if you have one). Or you could use Platform.getBundle.
You should not assume the url is a file on disk, for exactly the case when the plugin is a jar. You can use URL.openStream to get the contents, or FileLocator.toFileURL() to get a file on disk.

Related

What is a bundle resource path in class loader? How do I access that path?

I have a web application deployed to Websphere and found that there are some conflicting jars. To find the path of the conflicting class I have added the below code
ClassLoader classLoader = MyClass.class.getClassLoader();
URL resource = classLoader.getResource("org/apache/http/conn/ssl/AllowAllHostnameVerifier.class");
System.out.println(resource);
When I check the IBM System.out log file I see the below path for resource. I am not sure what bundle resource path is. I would like to know how do I access the below location?
bundleresource://85.fwk734572965/org/apache/http/conn/ssl/AllowAllHostnameVerifier.class
"bundleresource" URLs represent entries from the OSGi framework class loader. The number maps to a bundle number in the OSGi configuration, which you can find by opening up the OSGi console (from the WAS_HOME/bin directory, osgiConsole.sh|bat -server <servername>) and running the "ss" command, which lists the bundles along with their state and numerical ID.
Assuming you're seeing a conflict at runtime through class loading (not actually pulling in these classes through getResource), I'll say with fairly strong certainty that you're picking up the conflicting classes from the JAX-RS prereq jar, WAS_HOME/plugins/com.ibm.ws.prereq.jaxrs.jar. At the time it shipped, that jar made its copy of Apache HTTP visible to applications. That visibility was removed in a later fixpack, if you're able to patch up your installation to the latest service level.
Note that even if you move to a newer fixpack with that fix, your testcase will probably still show the same thing - I don't think that getResource() is subject to the same filtering as loadClass(), so you might still be able to get at the .class file in that manner. It might help with the issues you're seeing at runtime, though.

Websphere Liberty Profile Can't find bundle for base error

I have an EAR installed in eclipse on WLP 8.5.5.3
This is the EAR entry with a classloader attached:
<enterpriseApplication id="App4EAR" location="App4EAR-4.1.5-SNAPSHOT.ear" name="App4EAR">
<classloader apiTypeVisibility="spec,ibm-api,api" delegation="parentFirst" commonLibraryRef="baseLibraries.app4">
</classloader>
</enterpriseApplication>
The server is starting without issues. The first jsp page in the application tries to read a properties file which is located in the WAR component. This is where it fails.
SRVE0777E: Exception thrown by application class 'java.util.ResourceBundle.throwMissingResourceException:1427'
java.util.MissingResourceException: Can't find bundle for base name prop.appadmin, locale nl_BE
The object that reads the properties is located in the web application together with the properties file. The utility class for reading the resource bundle is in a separate jar and is part of a shared library (baseLibraries.app4).
This is an entry from the App4EAR.ear.xml deployment definition that points to folder where the properties file is located:
<dir sourceOnDisk="C:\svn\app4\App4Web\target\classes" targetInArchive="/WEB-INF/classes"/>
When using java.util.ResourceBundle() directly in the application it successfully locates the properties file. But not so when we use the utility class from the shared library.
Why is a shared library not able to access properties resources in the main web application?
Your shared library is loaded in parent classloader, and the classes and also properties in your application are not visible to that classloader thats why they cannot be found. Add property files to the classpath of the library instead of web app.
Packaging the utility jar, that accesses the resource file, in the web application solves the problem.
This solution kind of negates the purpose of shared libraries. Also note that on WAS 8.5 this was not a problem, so something did change in the way shared libraries are exposed/loaded.

Spring Webflow 2.3 Testing (with Maven): How to reference parent flow with filename different from id

I debugged my Spring Webflow test to the point of figuring out the first part of the issue: When you have a flow with a filename that is not the same as the id of the flow ('commons-flow.xml' with id='commons') then just using resourceFactory.createFileResource(pathToFlowFile) does not work because that assumes the id is the filename.
There is a method available to override the id, resourceFactory.createResource(pathToFlowFile, attributesMap, overrideId)
However, this uses the Classloader to resolves files whereas it seems the createFileResource used a different means.
I cannot figure out how I am supposed to get the Classloader to recognize the flow files. I inspected it's classpaths and it only has the JAR dependencies and then dynamically created target/classes and target/test-classes folders. No reference to my project.
This is a Maven project, and the path I have from project root to flows is something like:
src/main/webapp/WEB-INF/flows/<flow-folder>/<flow-filename>.xml
I have seen webflow testing, unable to find flow model which reiterates what I discovered already, but for some reason I have the issue with the Classloader that other seems not to have.
Where I see people successfully referencing the flow files, they seem to either be relative from the project root or relative from the WebContext at src/main/webapp.
I am running the JUnit test with a Run Configuration in Eclipse and also with the maven test goal.
It is possible for me to configure a custom classpath for the Run Configuration in Eclipse to include the parent folder of the relative path I have defined as pathToFlowFile.
However, that does not help at all with Maven, which has the classloader/classpath issue still when executing the test goal.
I ran into something similar where I had to set the flow id and specify the path. So instead of using the FlowDefinitionResourceFactory I created a FlowDefinitionResource instance like below
FlowDefinitionResource resource = new FlowDefinitionResource(flowId, path, attributes);
So in your method you should have something like this
protected FlowDefinitionResource[] getModelResources(FlowDefinitionResourceFactory resourceFactory) {
FlowDefinitionResource resource = new FlowDefinitionResource("flowId", src/main/webapp/WEB-INF/flows/<flow-folder>/<flow-filename>.xml", null);
return new FlowDefinitionResource[] {resource};
}
If you get a FileNotFoundException just check the stacktrace to see where it is looking for the file.
Hope this helps.
M

Packaging GWT module jar

I have created a GWT-loadable module (maven) with this output jar structure (using mvn package command):
mygwtlibrary
->src/main/java
-->org.mygwtlib
---->public
------>flash.swf
-->org.mygwtlib.client
---->MyClientCode.class
However when I run a application that use this library, error shows: Error 404 for fetching the flash.swf file.
Here's the scenario:
I have setup the project properly, including the <inherits> in the gwt.xml file
When I just include the whole library project into another GWT application project then run, it works fine. That is, the files from the public folder is loaded too.
What could be the problem?
The problem is that you're trying to fetch the flash.swf file over HTTP. This is (at best) bad practice. A better approach (by no means the only alternative) would be pulling it in as a resource which lives in your code. One way to do such a thing would be using Spring's ClassPathResource (or less preferably, FileSystemResource).

How to import user libraries programmatically from a file

I have "myUserLib.userlibraries" file with all the required user libraries defined. As part of my plug-in that i developed (this will create web projects and required settings), i want to import this file to the projects created by the plug-in.
Is there any programatic way to import libraries from a file?
If you are developing a plugin to add these libraries to project classpath, I recommend that you consider writing a custom classpath container rather than re-using the user libraries facility. If you write a custom container, project classpath would include id of your container and JDT will query your code at runtime to get the actual list of classpath entries.
This will save you from having to store and maintain the contents of your library in workspace preferences, as you would have to do if you took the user library approach.
See org.eclipse.jdt.core.IClasspathContainer class.
Finally i got this worked the way i want. I am now able to programmatically upload the userlibraries into workspace preferences from "myuserlibs.userlibraries" file. I used following eclipse plugins classes.
org.eclipse.jdt.internal.core.UserLibrary.class
org.eclipse.jdt.internal.core.UserLibraryManager.class
org.eclipse.jdt.internal.core.UserLibraryClasspathContainer.class
org.eclipse.jdt.internal.core.UserLibraryClasspathContainerInitializer.class
These classes have bunch of methods to achieve this task.
Once they got uploaded in to preferences, i am also able to programmatically add required user library entries into a respective projects (created by my plugin). Because i have around 8 web projects in my workspace and all of them required different set of user libraries in their classpath container.