Programmatic Logging Configuration in OSGi

9 12 2010

Although you can configure Logging via configuration files and admin consoles in OSGi, Sling/Felix in this instance, can you do it programatically. First, why would you want to. Well you might have a bundle, embedding a sub component where the logging verbosity is more than you want in the main logs. Obviously you can configure this bundle by adding config files, but thats not so easy if the config is outside the bundle, and you might want to put the logging configuration under the control of bundle itself on activation.  In Sling Logging is configured by via a Factory, which you can get hold of via the ConfigurationAdmin service provided by OSGi.

Configuration logConfiguration = configurationAdmin.createFactoryConfiguration("org.apache.sling.commons.log.LogManager.factory.config", null);
Dictionary<String, Object> loggingProperties = new Hashtable<String, Object>();
loggingProperties.put("pid", this.getClass().getName());
loggingProperties.put("org.apache.sling.commons.log.level", "INFO");
loggingProperties.put("org.apache.sling.commons.log.file", "logs/solr.log");
loggingProperties.put("org.apache.sling.commons.log.names", "org.apache.solr");
logConfiguration.update(loggingProperties);




Solr 4 OSGi Bundle

4 12 2010

I need a Solr bundle to provide search capabilities to my app, but I want it to work in a cluster, and I have to have near real time search indexing, so using SolrJ4 makes sense. On the Solr 4 road map it looks like a strong probability that it will be possible to configure for Near Real Time Search indexing in Solr based on the capabilities that were introduced into Lucene in version 2.9. So the approach is to create an OSGi bundle based on the 4.0-SNAPSHOT version of Solr, that will operate SolrJ in two modes. Remote for a cluster implementation where one or more Solr servers can provide search capabilities to the cluster, and Embedded where the App server cluster is a cluster of 1. My environment is based on Sling, which is OSGi. In some senses this make life easier as the classloader policies of OSGi allow me to isolate dependencies used by complex components such as Solr. On the other hand OSGi makes life harder since it requires that no cleaver tricks have been played with the underlying classloaders. Solr has a SolrResourceLoader that adds some custom package resolution and classloader structure which by default wont work in OSGi, so here is how to bring up Solr 4 Embedded as an OSGi component. At this point I have to give credit to Josh Holtzman working on the Matterhorn project for his pointer. He did this with Solr 1.3 a long time ago, and was kind enough to give me pointers.

The SolrConfig has a package protected constructor that allows the caller to give it a SolrResourceLoader which can be made to work with OSGi bundle class loader. Being a package protected constructor you will need to create this class in the same package as SolrConfig.

package  org.apache.solr.core;

import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrResourceLoader;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.ParserConfigurationException;

public class NakamuraSolrConfig extends SolrConfig {
 public NakamuraSolrConfig(SolrResourceLoader loader, String name, InputStream is)
      throws ParserConfigurationException, IOException, SAXException {    
    super(loader, name, is);  
 }
}

Having exposed the constructor (Solr people are now tut tutting), I can inject a custom SolrLoader with a modified openResource method to ensure we don’t fall foul of the OSGi classloader policy. The only part of the SolrLoader I significantly was:

@Override
public InputStream openResource(String resource) {
  InputStream in = this.getClass().getClassLoader().getResourceAsStream(resource);
  if ( in == null ) {
    in = super.openResource(resource);
  }
  return in;
}

 

With that all done I can construct an EmbeddedSolrServer

NakamuraSolrResourceLoader loader = new NakamuraSolrResourceLoader(solrHome,this.getClass().getClassLoader());
coreContainer = new CoreContainer(loader);
SolrConfig config = new NakamuraSolrConfig(loader, "solrconfig.xml", getStream("solrconfig.xml"));
IndexSchema schema = new IndexSchema(config, null, getStream("schema.xml"));
SolrCore nakamuraCore = new SolrCore("nakamura", coreDir.getAbsolutePath(), config, schema, null);
coreContainer.register("nakamura", nakamuraCore, false);
server = new EmbeddedSolrServer(coreContainer, "nakamura");

Obviously I also had to embed the jars I didn’t want as bundles and provide those I did, but the process of building the bundle itself is a bit too tedious to mention, and I haven’t finished that yet. I suspect I will encounter more problems although with full access to the resource loader I should be able to modify the behaviour appropriately.

 





Java Web Start for server applications

4 12 2010

If you want to make a Java Web Start distribution of a web application server built by maven, the there is a neat plugin to make it a bit easier, webstart-maven-plugin from org.codehaus. However, even if you give it full permissions and sign everything correctly, it probably wont work as the SecurityManager that the Java Web Start Client uses is going to stop all sorts of things, like finding the current users home directory, that a normal server app would have no problem with. So, first make certain that you have

<security>     
   <all-permissions/>
</security>

In the jnlp file.

That will give you just enough permissions to replace the security manger on the main class. If you do this before chaining to your real main class you probably wont have to change you app. All of this assumes that you app doesn’t actively do something with its own security manager and policy file.

package org.sakaiproject.nakamura.app;
import org.apache.sling.launchpad.app.Main;
public class JNPLMain {  
     public static void main(String[] args) {
           System.setSecurityManager(null);
           Main.main(args);        
      }
}







Follow

Get every new post delivered to your Inbox.

Join 121 other followers