Can't get a Mule flow-reference to recognize imported resource (external flow) from an external jar - mule

I cannot get a flow or a sub-flow that is in an external Mule application to display in the Flow name: drop-down of the Flow-Reference component of another project (my main project).
I have closely followed the example here from the MuleSoft documentation regarding the sharing of fragments.
It all works as per the tutorial, except I cannot get the external flow/sub-flow's name to appear in the drop-down of the main project's Flow-Reference component.
All of the maven stuff is fine.
The dependency is properly coded in the main Project's POM.
The jar displays in the Referenced Libraries.
The jar contains the application file I need (common-mule.xml).
If I force an error, by temporarily changing the name of import
resource, it correctly throws a not-found message. So, I know the
classpath is finding this external resource just fine.
BUT... when I double-click my Flow-Reference in the main project, I am not able to see the external flow in the flow names drop down.
Am I wrong about how this should work?

I tried doing the same thing and it is possible using the XML editor. My findings were -
If you are using maven the referenced project must be packaged as a jar and must be available on the referencing project's classpath.
You can refer to these for linking details:
https://docs.mulesoft.com/mule-user-guide/v/3.7/sharing-custom-code
https://docs.mulesoft.com/mule-user-guide/v/3.5/sharing-custom-configuration-fragments
After importing the xml as resource, you can simply type in the flow name in flow-ref and use it. It will give an error in the studio UI but the project is successfully built and the referenced flow is used as expected at runtime.
Its the bug with Studio UI only.

Make sure to use import of the flows in jar in your main project.
<spring:beans>
<spring:import resource="classpath:source_flow.xml"/>
<spring:import resource="classpath:global-config.xml"/>
</spring:beans>

Studio doesn't load elements from configuration files in JARs located on the build-path, so what you're trying to do is impossible (at least, currently).

Related

Mule ClassNotFoundException for class existing in a library in the class path

I have a class in a Mule application which resides in a jar of a third party library. The library gets included in the lib folder after the project builds so it is definitely in the classpath. The class is then used in a Mule component. The applications deploys successfully in AnyPoint Studio'sembedded server. However, when the Mule component is processing data, Mule complains that it can't find the class.
As soon as the line with the following code snippet is encountered it throws the NoClassDefFoundError.
populator.put(ScanType.MRI,container);
Here is a portion of the stacktrace:
Root Exception stack trace:
java.lang.ClassNotFoundException: com.tcfg.utils.defn.Populator
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at org.mule.module.launcher.FineGrainedControlClassLoader.findClass(FineGrainedControlClassLoader.java:175)
at org.mule.module.launcher.MuleApplicationClassLoader.findClass(MuleApplicationClassLoader.java:134)
at org.mule.module.launcher.FineGrainedControlClassLoader.loadClass(FineGrainedControlClassLoader.java:119)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
I also know that this is the only instance of the class in the whole project when I use a tool to search the entire lib folder for instances of the class. This is definitely not a situation of multiple versions of the class or of other classes existing in one of the jars with a similar name. What could be the cause of this and how can I resolve it?
Even though if you add the jar in lib folder you need to manually add that jar to your class path.So, that it will be available.
They are 2 possibilities here one is there might be a need of OS specific library to be downloaded and configured in Anypoint Stduio in Run configurations like for SAP we need to point it to the DLL which windows will refer to. Giving below an example.
-Djava.library.path=C:\Users\adm-snandu\AnypointStudio\workspace\
For most of the Class Notfound errors you need to make sure the maven dependency is given in the pom.xml which takes care of downloading all the relevant libraries and referring to them during run time.

How to make a resource file visible to all bundles in OSGi?

I'd like to include a resource file (e.g. some xml config file) in my bundle and make it visible to all other bundles in the container. Is it possible without using the Fragment-Host manifest header? I'd like this resource file to always be visible in the classpath of all bundles running alongside my bundle, even those that do not exist yet, but will potentially be added in future.
EDIT:
To clarify - that resource must be available passively, i.e. the other bundles should be able to find it in their classpath, and not by refering to any special API or service of my bundle.
Some more background - my environment is a bit messy but I have no control over it and cannot change its existing bundles. The only way I can modify it is by adding my own bundles. That environment includes several copies of the ch.qos.logback.classic bundle. When logback starts up, it looks for specific XML config files in the classpath. If it doesn't find any of them, then its default behaviour is to print everything to stdout with debug level. This environment was previously used to host a GUI application so it didn't matter that much before, but now I am trying to adapt it so I can use some of its functionality in headless mode. So now it becomes important to me to be able to configure it in such a way that only warning and errors are printed to the console.
In general, no you cannot do this. Class-space isolation is at the heart of OSGi, but you want to put a resource in the class loader of one bundle and make it visible to all other bundles. That's not OSGi, it's the global application classpath.
The only thing you can do to add to the internal classpath of a specific bundle is to write a fragment which attaches to that bundle. A fragment can attach to multiple host bundles, but only if those hosts have the same symbolic name, i.e. because they are different versions of the same bundle. See OSGi R6 Core Specification, section 3.14.
You did however state that the bundles you want to attach are all copies of ch.qos.logback.classic. If that means they all have that exact symbolic name then perhaps a fragment will work after all.
You can not change the classpath of other bundles this way.
What you can do is retrieve the classloader of your bundle from your bundleContext. You can give this classloader to another bundle to retrieve your resource.
ClassLoader cl = context.getBundle().adapt(BundleWiring.class).getClassLoader();
Another option is to give the other bundle the URL of the resource.
As long as the resource is on the classpath, any bundle can access the resource if it can get hold of the class loader of the bundle that contains the resource.
For example:
ClassLoader classLoaderOfBundleWithResource = ...
classLoaderOfBundleWithResource.getResourceAsStream("org/example/resource.xml");
From a maintenance and API point of view, I would not recommend exposing a resource that way. Java types are much better suited therefore. Instead, let the resource bundle export a class that gives clients access to the contents of the resource.
For example:
public class XmlDocumentProvider {
public InputStream openDocument() {
return getClass().getResourceAsStream("resource.xml");
}
}
Assuming that both the resource.xml and the XmlDocumentProvider reside in the same package, openDocument will return the resource content just like in the first example.

mule anypoint studio class not found exception

If I run the application in server, which is working fine, but If i run application in anypoint studio doesn't run. Here is the error message for loading oracle driver.
error message:
2015-02-04 11:18:34 WARN DriverManagerDataSource:107 - Could not load driverClass oracle.jdbc.OracleDriver
java.lang.ClassNotFoundException: oracle.jdbc.OracleDriver
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
I have placed all jdbc and other jars under studio->project->properties->libraries.
This is caused by the Studio's classloading policies. The workaround is to copy the JDBC Driver .jar to ${studio.home}/plugins/org.mule.tooling.server.${mule.version}.ee_${mule.version}.${release.date}/mule/lib/user
Hi there actually that's kind of a hack :P though it works.
The more proper way to deal with this is, when coding your application (that's why one should use Mule Studio), to place the jars like drivers in a particular folder, like a /lib in the root of you project.
Then add these jars to the classpath.
I know what you did is the way it should be done when running on Mule stand alone in order to share such jars but try this one if you can ;)
I was also facing the same problem. As the application runtime fails to locate the jdbc driver jar in classpath So It is unable to load the same.
the simple and easiest way to handle this error is just put your lib folder containing the ojdbc jar file inside the app resource (src/main/app) of the project. During the building of project it will automatically be place in classpath.
I have tried the same approach and It works for me.
Hope this helps.
The way I fixed the problem was removing the .classpath / .project files from my project root folder. I re-imported the project and then I saw a bin folder created. I removed this bin folder then right-click on the project -> Refresh and then Run As -> Mule Application.

Add class to build path using Mule Studio

I'm using Anypoint Studio with Mule Server 3.5.0 CE.
I have a custom transformer named CustomAsyncTransformer which is defined in the class AsyncTransformer.
Within one of my Mule flows:
<custom-transformer name="CustomAsyncTransformer" class="ca.mpac.esb.component.webservice.AsyncTransformer">
</custom-transformer>
This causes the following message to be displayed:
Unable to find type 'ca.mpac.esb.component.webservice.AsyncTransformer' on build path of project TEST-PROJECT
However, AsyncTransformer.class has been added to the build path; it is located in src/main/app which is designated as a source folder. I've also tried adding it directly to the build path, creating a new source folder, and adding it to other source folders. Still no change.
What am I doing wrong? How can I add this class to the build path?
Java source code should be in src/main/java. So your approach to add add a new source folder is correct, just use src/main/java so your Maven build will pick it up too.
Studio should pick the class from it. If it's not the case, it's maybe a bug? Or maybe something else: to find out show a screenshot of your application directory layout.

How do I add my fragment to the list of required-plugins on an existing plugin

I currently have an existing plugin, which references a class from a required plugin. I have replaced this code with a reference to a class which is part of my fragment.
I am facing two issues.
If I import my fragment as a jar file, I am not able to see the changes I have made as the plugin running as an eclipse application results in a ClassNotFoundException
To overcome this, I link an additional source (of fragment) to the existing plugin project. However, the link uses an absolute path, and makes it unfit for deployment.
I want to be able to package the plugin with the code modification and be able to "depend" on my fragment code. Is there a way I can add my fragment as a dependency?
For example:
Plugin Project I am changing : org.eclipse.*.editor
it depends on org.eclipse.*.edit
I have a fragment mydomain.*.edit which has org.eclipse.*.edit as host plugin
I want org.eclipse.*.editor to pick up mydomain.*.edit
instead of org.eclipse.*.edit
ps: I have also tried packaging the jar file for the mydomain.*.edit in the plugins directory and try and pick it up from there, it doesnt show up on the list when I click add required plugins on the dependency tab on the plugin.xml file of the org.eclipse.*.editor
Please let me know if I am not clear enough, I will try and rephrase it.
Thanks in advance!
If I understand correctly what you want to do, I don't think that it's possible. You will have to try some other way.
Plugins have dependencies on other plugins. Fragments don't exist as separate runtime entities, but only as extensions of a plugin. So your plugin can only refer to the 'editor' plugin.
Classes provided by a fragment can't (and shouldn't) be accessed directly. They can be returned by the original plugin (A) if they are implementing an executable extension provided by plugin A.
If you refer to the fragment's code from another plugin (B), the classes will be loaded by plugin B's classloader and be different from the ones that are loaded by plugin A.
What is the purpose of your fragment? Do you want to get access to internal code in plugin A? Do you want to extend an eclipse editor?
If you want to extend functionality that the original plugin is not exposing as extensible, I think the only way is to write a plugin, extend the editor class from the original plugin, register it alongside the original one and use it instead.
[Edit] Maybe this link will explain better: Eclipse FAQ
Hope this helps,
Vlad
Thanks Vlad,
Your explanation was very helpful. Unlike the extension based architecture that is truly intended for fragments, I had to modify a certain component in the editor that was not exposed as part of the extension. This modification referred to an external project I created as an fragment but could have been a normal java project packaged a jar file that I could place in the classpath of the editor.
I was able to resolve the dependency issues by placing the jar file in class path, however when I export the plugins and related plugins as jar files and place it in the dropin directory, it does not install correctly. (Nor does placing the jar files in the plugins directory)
The eclipse editor that I am trying to modify uses the EMF project. I have kept the EMF project in the workspace inorder to resolve dependencies of the editor. However when I replace the EMF jar files bundled with eclipse with the one in the workspace, the files that I want to edit are not correctly recognized.
Is there another way of doing this?