package hudson.drools; import hudson.security.ACL; import hudson.util.IOException2; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import java.util.Collection; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContextHolder; import org.drools.KnowledgeBase; import org.drools.KnowledgeBaseFactory; import org.drools.SessionConfiguration; import org.drools.builder.KnowledgeBuilder; import org.drools.builder.KnowledgeBuilderError; import org.drools.builder.KnowledgeBuilderErrors; import org.drools.builder.KnowledgeBuilderFactory; import org.drools.builder.ResourceType; import org.drools.common.InternalWorkingMemory; import org.drools.common.InternalWorkingMemoryEntryPoint; import org.drools.compiler.PackageBuilderConfiguration; import org.drools.definition.KnowledgePackage; import org.drools.definition.process.Process; import org.drools.impl.EnvironmentFactory; import org.drools.io.impl.ReaderResource; import org.drools.marshalling.Marshaller; import org.drools.marshalling.MarshallerFactory; import org.drools.marshalling.impl.ProcessMarshallerRegistry; import org.drools.ruleflow.core.RuleFlowProcess; import org.drools.runtime.Environment; import org.drools.runtime.KnowledgeSessionConfiguration; import org.drools.runtime.StatefulKnowledgeSession; public class DroolsSession { private static Logger LOGGER = Logger.getLogger(DroolsSession.class.getName()); private final StatefulKnowledgeSession session; private final KnowledgeBase kbase; private final Marshaller marshaller; private final String processId; private File saved; public StatefulKnowledgeSession getSession() { return session; } public KnowledgeBase getKbase() { return kbase; } public String getProcessId() { return processId; } public DroolsSession(File saved, String processXML, int initialProcessInstanceId) throws IOException { this.saved = saved; KnowledgeBuilder kbuilder = KnowledgeBuilderFactory .newKnowledgeBuilder(new PackageBuilderConfiguration()); kbuilder.add(new ReaderResource(new StringReader(processXML)), ResourceType.DRF); KnowledgeBuilderErrors errors = kbuilder.getErrors(); StringBuilder sb = new StringBuilder(); if (errors.size() > 0) { for (KnowledgeBuilderError error : errors) { sb.append(error.getMessage()).append("\n"); } throw new IllegalArgumentException("Could not parse knowledge:\n" + sb); } Collection<KnowledgePackage> knowledgePackages = kbuilder .getKnowledgePackages(); Process process = knowledgePackages.iterator().next().getProcesses() .iterator().next(); processId = process.getId(); kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages(knowledgePackages); marshaller = MarshallerFactory.newMarshaller(kbase); SessionConfiguration conf = new SessionConfiguration(); Properties p = new Properties(); p.setProperty("drools.processInstanceManagerFactory", HudsonProcessInstanceManagerFactory.class.getName()); conf.addProperties(p); Environment env = EnvironmentFactory.newEnvironment(); if (!saved.exists() || saved.length() == 0) { session = kbase.newStatefulKnowledgeSession(conf, env); } else { InputStream is = null; try { is = new FileInputStream(saved); session = marshaller.unmarshall(is, conf, env); } catch (ClassNotFoundException e) { throw new IOException2("Class not found while unmarshalling " + saved.getAbsolutePath(), e); } catch (IOException e) { throw new IOException2("Error while unmarshalling " + saved.getAbsolutePath(), e); } finally { is.close(); } } ((HudsonProcessInstanceManager) ((InternalWorkingMemoryEntryPoint) session) .getInternalWorkingMemory().getProcessInstanceManager()) .setProcessCounter(initialProcessInstanceId); } public synchronized void save() throws IOException { OutputStream os = null; try { File newSaved = new File(saved.getParentFile(), saved.getName() + ".new"); File backupSaved = new File(saved.getParentFile(), saved.getName() + ".bak"); os = new FileOutputStream(newSaved); marshaller.marshall(os, session); os.close(); os = null; if (backupSaved.exists()) { if (!backupSaved.delete()) { throw new IOException("could not remove backup " + backupSaved.getAbsolutePath()); } } if (saved.exists()) { if (!saved.renameTo(backupSaved)) { throw new IOException("could not backup " + saved.getAbsolutePath()); } } if (!newSaved.renameTo(saved)) { backupSaved.renameTo(saved); throw new IOException("could not rename " + saved.getAbsolutePath()); } } finally { if (os != null) os.close(); } } public void dispose() { session.dispose(); } public synchronized <T> T run(SessionCallable<T> callable) throws Exception { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Authentication auth = SecurityContextHolder.getContext().getAuthentication(); try { SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); Thread.currentThread().setContextClassLoader( getClass().getClassLoader()); T result = callable.call(session); save(); return result; } catch (Exception e) { LOGGER.log(Level.WARNING, "Exception while running " + callable + " on " + processId, e); throw e; } finally { SecurityContextHolder.getContext().setAuthentication(auth); Thread.currentThread().setContextClassLoader(cl); } } }