How to enable Rhino (or any JavaScript Engine) in CQ 5.6? - osgi

I have some custom logic where I need to evaluate a simple boolean expression. In my IDE I have some unit tests that run fine, but when I'm trying to use it on my CQ 5.6.1 instance, the ScriptEngineManager can't find a JavaScript engine. Though this should be part of a standard java installation on any environment.
ScriptEngineManager sef = new ScriptEngineManager();
ScriptEngine se = sef.getEngineByName("JavaScript");
In the pom I have the following which usually helps:
<Import-Package>*;resolution:=optional</Import-Package>
Usually some system libraries aren't exposed in OSGi when you don't put it into the bootdelegation in the sling.properties, but this didn't work either:
org.osgi.framework.bootdelegation=org.w3c.*,com.sun.script.*,com.yourkit.*, ${org.apache.sling.launcher.bootdelegation}
What else could I try?
EDIT:
Also regarding my comment to Christians answer. I found out that there should be a service in the OSGi:
http://svn.apache.org/repos/asf/sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineFactory.java
But when I try to reference it with the following code, my servlet isn't active anymore:
#Reference
private transient ScriptEngineFactory sef = null;
So it seems it can't inject the factory for some reason. I've seen there could be more than one service implementing this interface, how would I target the correct one (linked above)?
EDIT2:
I now even tried to reference the Rhino factory directly:
#Reference(target = "(component.name=org.apache.sling.scripting.javascript.internal.RhinoJavaScriptEngineFactory)")
private transient ScriptEngineFactory sef = null;
With this my servlet tells me it is satisfied:
["Satisfied","Service Name: javax.script.ScriptEngineFactory","Target Filter: (component.name=org.apache.sling.scripting.javascript.internal.RhinoJavaScriptEngineFactory)","Multiple: single","Optional: mandatory","Policy: static","Bound Service ID 2004 (org.apache.sling.scripting.javascript.internal.RhinoJavaScriptEngineFactory)"]
But if I access my servlet it doesn't get triggered and the SlingDefaultServlet takes over. Without the above #Reference it is accessible, so it has to do something with it.

You need an OSGi capable ScriptEngineManager. See https://devnotesblog.wordpress.com/2011/09/07/scripting-using-jsr-223-in-an-osgi-environment/

After almost a whole day of trial and error I found 2 major problems:
First: My compiler plugin was set to use 1.8; I had to revert that to 1.6 so my maven-scr-plugin would create proper manifests again and injection of OSGi services actually works:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
I have to investigate later how it would be possible to increase that to at least 1.7 (I tried but didn't work either).
Second and the actual answer for my question is simple:
#Reference
private transient ScriptEngineManager sem = null;
Also I had to use javascript instead of JavaScript for the getEngineByName method from the manager. To see what is registered for the engine, you can check out the following path in your OSGi console:
/system/console/status-slingscripting
There all available ScriptEngine are listed with their registered names, extensions and MIME Types.

Related

Override a Service in Grails using Spring Bean declaration

I am creating a new plugin containing CustomService which is intended to replace an existing service from an existing plugin. Following the pattern found in custom security implementations and shown here, I've added the configuration to the resources.groovy, oldService(path.to.new.CustomService). I've also tried adding all injected classes into the closure for this service.
(Actual service names are RegistrationPersonRegistrationCompositeService and NewRegistrationPersonRegistrationCompositeService in code block)
I dont want the original application code to have any reference to the new plugin. However, BuildConfig at the application level will require plugin.location entry. My resource.groovy mods are in the new plugin. I have not had success in this endeavor. Am I modifying the wrong resources.groovy? If this change is required in the original application code, I've lost the ability to leave the original code unaltered. I'm not extending the original Service nor using override annotation. My intent is to replace the service (Spring bean) on start-up. The new plugin has a dependency on the old plugin in an attempt to manage order of operations in loading these classes.
Does it matter that the old service is previously injected in a controller? this would require me to override the controller in the new plugin in the same fashion and inject the correct service for desired behavior?
I've found documentation showing that within a plugin, the resources.groovy will be ignored. Also, building the resources.groovy into a war is problematic. I have not found a solution. I'm getting no error that I can share, just that the desired behavior is missing; the original service is handling the requests.
//was resource.groovy - now renamed to serviceOverRide.groovy - still located in \grails-app\conf\spring of plugin
//tried this with and without the BeanBuilder. Theory: I'm missing the autowire somehow
import org.springframework.context.ApplicationContext
import grails.spring.BeanBuilder
def bb = new BeanBuilder()
bb.beans {
registrationPersonRegistrationCompositeService(path.to.services.registration.NewRegistrationPersonRegistrationCompositeService) { bean ->
bean.autowire = true
registrationRestrictionCompositeService = ref("registrationRestrictionCompositeService")
registrationPersonTermVerificationService = ref("registrationPersonTermVerificationService")
}
classRegistrationController(path.to.services.registration.ClassRegistrationController) { bean ->
bean.autowire = true
selfServiceLookupService = ref("selfServiceLookupService")
registrationPersonRegistrationCompositeService = ref("registrationPersonRegistrationCompositeService")
}
}
ApplicationContext appContext = bb.createApplicationContext()
Additional information: Added the following lines to the PluginGrailsPlugin.groovy. The original service is still handling these requests
def dependsOn = ['appPersonRegistration': '1.0.20 > *']
List loadAfter = ['appPersonRegistration']
def doWithSpring = {
registrationPersonCourseRegistrationCompositeService(path.to.new.registration.TccRegistrationPersonCourseRegistrationCompositeService)
}
def doWithApplicationContext = { applicationContext ->
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory()
beanFactory.registerBeanDefinition("registrationPersonCourseRegistrationCompositeService", BeanDefinitionBuilder.rootBeanDefinition(TccRegistrationPersonCourseRegistrationCompositeService.class.getName()).getBeanDefinition())
}
I highly recommend you read the section of the documentation on Plugins. The reason why I recommend this is because plugins:
Do not include, or make use of resources.groovy
Provide a means through doWithSpring to effect the spring application
Following the information in the documentation you should have no issue overriding the service in the application context.
You must implement your changes to the application context using doWithSpring this is the key to solving your issues.
In this implementation, I had a utility method in a service for which I was attempting to provide an override. Problem is, the Aspect works as a proxy and must override a method that is called directly from another class. In my classRegistrationController, I was calling service processRegistration() which in turn called applyRules(). Example-only method names used. Since the service was calling its own utility, there was no opportunity for the proxy/wrapper to circumvent the call to applyRules(). Once this was discovered, I refactored the code in this fashion: Controller calls processRegistration as it always had. After returning, another call is made to the service, processLocalRules(). The new method is an empty placeholder intended to be overridden by the client's custom logic. The plugin with Aspect works now using resources.groovy. I prefer the doWithSpring as Joshua explained for this reason: my intent to get the plugin to work without modification to the original app-config; otherwise resource.groovy is a valid approach. Upvoting Joshua's answer as it does satisfy the requirement and is cleaner. Thanks!

Deploying BEAN in OSGi plugin

I am currently deploying my custom controls as OSGi plugins and I wanted to do the same thing with my beans. I have tried putting them into the OSGi plugin and it works fine but the only problem I have is the faces-config.
It seems it has to be called faces-config in the OSGi plugin to work but that means i can't use beans in the NSF anymore because it seems to ignore the local faces-config.
Is there a way to change the name of the faces-config in the OSGi plugin?
Something like FEATURE-faces-config.xml?
In the class in your plugin that extends AbstractXspLibrary, you can override "getFacesConfigFiles", which should return an array of strings representing paths within the plugin to additional files of any name to load as faces-config additions. For example:
#Override
public String[] getFacesConfigFiles() {
return new String[] {
"com/example/config/beans.xml"
};
}
Then you can put the config file in that path within your Java source folder (or another folder that is included in build.properties) and it will be loaded in addition to your app's normal faces-config, beans and all.
The NSFs are running as separate, distinct Java applications. The OSGi plugin is running in the OSGi layer, above all those distinct Java applications, as a single code base. Consequently, the faces-config is only at that level.
It's possible to load them dynamically, by using an ImplicitObjectFactory, loaded from an XspContributor. That's what is done in OpenNTF Domino API for e.g. userScope (which is a bean stored in applicationScope of an NSF). See org.openntf.domino.xsp.helpers.OpenntfDominoImplicitObjectFactory, which is referenced in OpenntfDominoXspContributor, loaded via the extension point of type "com.ibm.xsp.library.Contributor".
A few caveats:
You have no control over what happens if you try to register your bean with a name the developer also uses for a different variable in that scope.
Unless you add code to check if the library is enabled, as we do, you'll be adding the bean to every database on the server.
You still need to add the library to the NSF. Unless you also provide a component that those databases will all use, there's no way you can programmatically add it, as far as I know.
It might be easier to skip the bean approach and just add an instance of the Java class in beforePageLoad, page controller class, or however you're managing the backing to the relevant XPage (if viewScope) or application (if sessionScope / applicationScope).

OSGi bundle config without managed service or factory

Neil Bartlett's article http://njbartlett.name/2010/07/19/factory-components-in-ds.html shows the way to set config for bundles without using managed service or managed factory.
Search for examples of actually setting the config for this method either point to felix file install or to examples using managed service.
In answer to the question OSGi Declarative Services vs. ManagedService for configuring service? Neil Bartlett states "Note that DS never actually creates a ManagedService or ManagedServiceFactory for your component. It works by listening to Config Admin with a ConfigurationListener. However the internal details are unimportant... simply create configs with PID/factoryPID matching the component.name and it "just works"
I think the technique involves placing a pid entry in the config dictionary but I have no idea how this would be used with config admin.
A guide or simple example of how to set the configuration using this method would be very helpful.
I know it is some time since the question was asked, but I ran into the same problem when trying to create a ManagedServiceFactory-like Component with Declarative Services. So I want to share my solution. Maybe others find it useful. My problem was like this:
I have defined a component (annotated with #Component). On each configuration I add using felix file-install, I want an instance of that component created with the given configuration and activated immediately.
First I tried messing with the properties factory and configurationPid of #Component, but all that is not needed and even returns wrong results (felix annotation processor in the maven plugin seems to have a bug when handling configurationPid).
The solution I came up with:
package com.example.my;
#Component(
name = MyExampleComponent.FACTORY_PID,
configurationPolicy = ConfigurationPolicy.REQUIRE,
property = {"abc=", "exampleProp="}
)
public class MyExampleComponent {
public static final String FACTORY_PID = "com.example.my.component";
#Activate
protected void activate(BundleContext context, Map<String,Object> map) {
// ...
}
}
Then I created a config file for felix file-install named com.example.my.component-test1.cfg:
abc = Hello World
exampleProp = 123
When deployed this automatically creates a folder structure in the configuration folder like com/example/my/component containing the files:
factory.config
contents:
factory.pid="com.example.my.component"
factory.pidList=[ \
"com.example.my.component.525ca4fb-2d43-46f3-b912-8765f639c46f", \
]
.
525ca4fb-2d43-46f3-b912-8765f639c46f.config
contents:
abc="Hello World"
exampleProp="123"
felix.fileinstall.filename="file:/..._.cfg"
service.factoryPid="com.example.my.component"
service.pid="com.example.my.component.525ca4fb-2d43-46f3-b912-8765f639c46f"
The 525ca4fb-2d43-46f3-b912-8765f639c46f seems to be some randomly generated ID (possibly UUID).

MavenProject: Get the available classes for use on my plugin

I'm loading a Maven project as described here. I'm trying to figure out how I can retrieve the source roots so I can figure out the Java classes I have so my Mojo can use them.
I tried a couple of the methods in there, like getResources or getScriptSources without luck. Any idea?
Thanks in advance!
Edit:
I was asked to elaborate a little bit in what I'm attempting to do, so here it is:
The plugin I'm developing will take the sources in the project and create test cases from those. Unless configured, I want to generate tests for all the classes, and for that, I need to somehow figure out where are my sources so I can configure properly.
Hope that helps.
Here's the repository. I planned on publishing it later but I provided source as requested.
Have you read the plugin developers documentation?
That page will link to Plugins Cookbook which links to Mojo Developer Cookbook which has The maven project, or the effective pom. and gives you access to org.apache.maven.project.MavenProject object via
/** #parameter default-value="${project}" */
private org.apache.maven.project.MavenProject mavenProject;
Alternatively via Java 5 annotations
#Component
MavenProject project;
You can call getCompileSourceRoots() to get a list of the directories that will be used for compilation.
You will also need to do more reading about how to setup inclusion/exclusions. You can use other plugins as examples of how to do this, e.g. maven-compiler-plugin
If you want to use annotations, it is very important to make sure your pom is configured as per using annotations and that you use annotations at the class level as well. Mixing javadoc annotations might not work.
I think the simplest solution would be to define a mojo parameter:
/**
* #parameter default-value="${project.build.sourceDirectory}"
* #required
*/
private File sourceDirectory;
or with new annotation based definition:
#Parameter(required = true, defaultValue="${project.build.sourceDirectory}"}
private File sourceDirectory;
which should give your wished result.

Maven + Surefire/Failsafe - forkMode="perthread" is not working ... a workaround?

We are developing an application based in an Embedded Infinispan Data-grid cluster. In the targeted environment of our application, each member of the data-grid will run in a independent JVM and using jgroup the cluster will be formed (this is done by Infinispan actually).
For do some automated testing over this data-grid we were working with maven-surefire-plugin (or maven-failsafe-plugin) with this configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>perthread</forkMode>
<threadCount>4</threadCount>
</configuration>
</plugin>
Because this configuration should create a fork per each testcase class (using 4 parallel process) we create 4 test classes, where each one of them will simulate one cluster member. Inside each testcase class we will have several threads running in parallel the test methods thanks to TestNG like this:
#Test(threadPoolSize = 3, invocationCount = 2, timeOut = 10000, testName="Test 1")
public void testSomething() throws Throwable { ... }
The problem is that the maven-surefire-plugin forkMode="perthread" and threadCount=4 is buggy: It do not create one fork per class but a fork of the same class several times. So, in my scenario it takes one of the testcases and run it 4 times in parallel!!!
NOTE: check the jira bug here. Please vote!!!!
Do someone knows a workaround for this? We are doing some efforts using ant but is getting very messy.
The maven-surefire-plugin bug was resolved and it will be released in the version 2.13!
Check the Jira ticket for more info: http://jira.codehaus.org/browse/SUREFIRE-869

Resources