Java tutorial
/* * Copyright 2011 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.drools.guvnor.server; import com.google.gwt.user.client.rpc.SerializationException; import org.apache.commons.io.IOUtils; import org.drools.*; import org.drools.base.ClassTypeResolver; import org.drools.common.AbstractRuleBase; import org.drools.common.InternalRuleBase; import org.drools.common.InternalWorkingMemory; import org.drools.compiler.DrlParser; import org.drools.compiler.DroolsParserException; import org.drools.core.util.DroolsStreamUtils; import org.drools.guvnor.client.common.AssetFormats; import org.drools.guvnor.client.rpc.*; import org.drools.guvnor.server.builder.AuditLogReporter; import org.drools.guvnor.server.builder.ClassLoaderBuilder; import org.drools.guvnor.server.cache.RuleBaseCache; import org.drools.guvnor.server.contenthandler.ModelContentHandler; import org.drools.guvnor.server.security.PackageUUIDType; import org.drools.guvnor.server.security.RoleType; import org.drools.guvnor.server.util.LoggingHelper; import org.drools.ide.common.client.modeldriven.testing.Scenario; import org.drools.lang.descr.PackageDescr; import org.drools.lang.descr.TypeDeclarationDescr; import org.drools.repository.*; import org.drools.rule.Package; import org.drools.runtime.rule.ConsequenceException; import org.drools.testframework.RuleCoverageListener; import org.drools.testframework.ScenarioRunner; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.remoting.WebRemote; import org.jboss.seam.annotations.security.Restrict; import org.jboss.seam.contexts.Contexts; import org.jboss.seam.security.Identity; import java.io.IOException; import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; @Name("org.drools.guvnor.client.rpc.PackageService") @AutoCreate public class RepositoryPackageService implements PackageService { @In private RulesRepository repository; private static final long serialVersionUID = 901123; private static final LoggingHelper log = LoggingHelper.getLogger(RepositoryAssetService.class); private final ServiceSecurity serviceSecurity = new ServiceSecurity(); private final RepositoryPackageOperations repositoryPackageOperations = new RepositoryPackageOperations(); private final RepositoryAssetOperations repositoryAssetOperations = new RepositoryAssetOperations(); @Create public void create() { repositoryPackageOperations.setRulesRepository(getRulesRepository()); repositoryAssetOperations.setRulesRepository(getRulesRepository()); } /* This is called in hosted mode when creating "by hand" */ public void setRulesRepository(RulesRepository repository) { this.repository = repository; create(); } public RulesRepository getRulesRepository() { return repository; } /** * Role-based Authorization check: This method only returns packages that * the user has permission to access. User has permission to access the * particular package when: The user has a package.readonly role or higher * (i.e., package.admin, package.developer) to this package. */ @WebRemote @Restrict("#{identity.loggedIn}") public PackageConfigData[] listPackages() { return listPackages(null); } @WebRemote @Restrict("#{identity.loggedIn}") public PackageConfigData[] listPackages(String workspace) { RepositoryFilter pf = new PackageFilter(); return repositoryPackageOperations.listPackages(false, workspace, pf); } @WebRemote @Restrict("#{identity.loggedIn}") public PackageConfigData[] listArchivedPackages() { return listArchivedPackages(null); } @WebRemote @Restrict("#{identity.loggedIn}") public PackageConfigData[] listArchivedPackages(String workspace) { RepositoryFilter pf = new PackageFilter(); return repositoryPackageOperations.listPackages(true, workspace, pf); } public PackageConfigData loadGlobalPackage() { return repositoryPackageOperations.loadGlobalPackage(); } @WebRemote @Restrict("#{identity.loggedIn}") public void rebuildPackages() throws SerializationException { Iterator<PackageItem> pkit = getRulesRepository().listPackages(); StringBuilder errs = new StringBuilder(); while (pkit.hasNext()) { PackageItem pkg = pkit.next(); try { BuilderResult builderResult = this.buildPackage(pkg.getUUID(), true); if (builderResult != null) { errs.append("Unable to build package name [").append(pkg.getName()).append("]\n"); StringBuilder buf = createStringBuilderFrom(builderResult); log.warn(buf.toString()); } } catch (Exception e) { e.printStackTrace(); log.error("An error occurred building package [" + pkg.getName() + "]\n"); errs.append("An error occurred building package [").append(pkg.getName()).append("]\n"); } } if (errs.toString().length() > 0) { //throw new DetailedSerializationException( "Unable to rebuild all packages.", //errs.toString() ); } } private StringBuilder createStringBuilderFrom(BuilderResult res) { StringBuilder buf = new StringBuilder(); for (int i = 0; i < res.getLines().size(); i++) { buf.append(res.getLines().get(i).toString()); buf.append('\n'); } return buf; } @WebRemote @Restrict("#{identity.loggedIn}") public String buildPackageSource(String packageUUID) throws SerializationException { serviceSecurity.checkSecurityIsPackageDeveloperWithPackageUuid(packageUUID); return repositoryPackageOperations.buildPackageSource(packageUUID); } @WebRemote public String copyPackage(String sourcePackageName, String destPackageName) throws SerializationException { serviceSecurity.checkSecurityIsAdmin(); return repositoryPackageOperations.copyPackage(sourcePackageName, destPackageName); } @WebRemote @Restrict("#{identity.loggedIn}") public void removePackage(String uuid) { serviceSecurity.checkSecurityIsPackageAdminWithPackageUuid(uuid); repositoryPackageOperations.removePackage(uuid); } @WebRemote @Restrict("#{identity.loggedIn}") public String renamePackage(String uuid, String newName) { serviceSecurity.checkSecurityIsPackageAdminWithPackageUuid(uuid); return repositoryPackageOperations.renamePackage(uuid, newName); } @WebRemote @Restrict("#{identity.loggedIn}") public byte[] exportPackages(String packageName) { serviceSecurity.checkSecurityIsPackageAdminWithPackageName(packageName); return repositoryPackageOperations.exportPackages(packageName); } @WebRemote @Restrict("#{identity.loggedIn}") // TODO: Not working. GUVNOR-475 public void importPackages(byte[] byteArray, boolean importAsNew) { repositoryPackageOperations.importPackages(byteArray, importAsNew); } @WebRemote public String createPackage(String name, String description, String[] workspace) throws RulesRepositoryException { serviceSecurity.checkSecurityIsAdmin(); return repositoryPackageOperations.createPackage(name, description, workspace); } @WebRemote public String createPackage(String name, String description) throws RulesRepositoryException { return createPackage(name, description, new String[] {}); } @WebRemote public String createSubPackage(String name, String description, String parentNode) throws SerializationException { serviceSecurity.checkSecurityIsAdmin(); return repositoryPackageOperations.createSubPackage(name, description, parentNode); } @WebRemote @Restrict("#{identity.loggedIn}") public PackageConfigData loadPackageConfig(String uuid) { PackageItem packageItem = getRulesRepository().loadPackageByUUID(uuid); // the uuid passed in is the uuid of that deployment bundle, not the // package uudi. // we have to figure out the package name. serviceSecurity.checkSecurityIsPackageReadOnlyWithPackageName(packageItem.getName()); return repositoryPackageOperations.loadPackageConfig(packageItem); } @WebRemote @Restrict("#{identity.loggedIn}") public ValidatedResponse validatePackageConfiguration(PackageConfigData data) throws SerializationException { serviceSecurity.checkSecurityIsPackageDeveloperWithPackageUuid(data.getUuid()); return repositoryPackageOperations.validatePackageConfiguration(data); } @WebRemote @Restrict("#{identity.loggedIn}") public void savePackage(PackageConfigData data) throws SerializationException { serviceSecurity.checkSecurityIsPackageDeveloperWithPackageUuid(data.getUuid()); repositoryPackageOperations.savePackage(data); } @WebRemote @Restrict("#{identity.loggedIn}") public BuilderResult buildPackage(String packageUUID, boolean force) throws SerializationException { return buildPackage(packageUUID, force, null, null, null, false, null, null, false, null); } @WebRemote @Restrict("#{identity.loggedIn}") public BuilderResult buildPackage(String packageUUID, boolean force, String buildMode, String statusOperator, String statusDescriptionValue, boolean enableStatusSelector, String categoryOperator, String category, boolean enableCategorySelector, String customSelectorName) throws SerializationException { serviceSecurity.checkSecurityIsPackageDeveloperWithPackageUuid(packageUUID); return repositoryPackageOperations.buildPackage(packageUUID, force, buildMode, statusOperator, statusDescriptionValue, enableStatusSelector, categoryOperator, category, enableCategorySelector, customSelectorName); } @WebRemote @Restrict("#{identity.loggedIn}") public void createPackageSnapshot(String packageName, String snapshotName, boolean replaceExisting, String comment) { serviceSecurity.checkSecurityIsPackageAdminWithPackageName(packageName); repositoryPackageOperations.createPackageSnapshot(packageName, snapshotName, replaceExisting, comment); } @WebRemote @Restrict("#{identity.loggedIn}") public void copyOrRemoveSnapshot(String packageName, String snapshotName, boolean delete, String newSnapshotName) throws SerializationException { serviceSecurity.checkSecurityIsPackageAdminWithPackageName(packageName); repositoryPackageOperations.copyOrRemoveSnapshot(packageName, snapshotName, delete, newSnapshotName); } @WebRemote @Restrict("#{identity.loggedIn}") public String[] listRulesInPackage(String packageName) throws SerializationException { serviceSecurity.checkSecurityIsPackageReadOnlyWithPackageName(packageName); return repositoryPackageOperations.listRulesInPackage(packageName); } @WebRemote public void rebuildSnapshots() throws SerializationException { serviceSecurity.checkSecurityIsAdmin(); Iterator<PackageItem> pkit = getRulesRepository().listPackages(); while (pkit.hasNext()) { PackageItem pkg = pkit.next(); String[] snaps = getRulesRepository().listPackageSnapshots(pkg.getName()); for (String snapName : snaps) { PackageItem snap = getRulesRepository().loadPackageSnapshot(pkg.getName(), snapName); BuilderResult builderResult = this.buildPackage(snap.getUUID(), true); if (builderResult.hasLines()) { StringBuilder stringBuilder = createStringBuilderFrom(builderResult); throw new DetailedSerializationException("Unable to rebuild snapshot [" + snapName, stringBuilder.toString() + "]"); } } } } @WebRemote @Restrict("#{identity.loggedIn}") public SnapshotInfo[] listSnapshots(String packageName) { serviceSecurity.checkSecurityIsPackageDeveloperWithPackageName(packageName); String[] snaps = getRulesRepository().listPackageSnapshots(packageName); SnapshotInfo[] res = new SnapshotInfo[snaps.length]; for (int i = 0; i < snaps.length; i++) { PackageItem snap = getRulesRepository().loadPackageSnapshot(packageName, snaps[i]); SnapshotInfo info = new SnapshotInfo(); res[i] = info; info.comment = snap.getCheckinComment(); info.name = snaps[i]; info.uuid = snap.getUUID(); } return res; } @WebRemote @Restrict("#{identity.loggedIn}") public String[] listTypesInPackage(String packageUUID) throws SerializationException { serviceSecurity.checkSecurityPackageReadOnlyWithPackageUuid(packageUUID); PackageItem pkg = this.getRulesRepository().loadPackageByUUID(packageUUID); List<String> res = new ArrayList<String>(); AssetItemIterator it = pkg.listAssetsByFormat(AssetFormats.MODEL, AssetFormats.DRL_MODEL); JarInputStream jis = null; try { while (it.hasNext()) { AssetItem asset = (AssetItem) it.next(); if (!asset.isArchived()) { if (asset.getFormat().equals(AssetFormats.MODEL)) { jis = typesForModel(res, asset); } else { typesForOthers(res, asset); } } } return res.toArray(new String[res.size()]); } catch (IOException e) { log.error("Unable to read the jar files in the package: " + e.getMessage()); throw new DetailedSerializationException("Unable to read the jar files in the package.", e.getMessage()); } finally { IOUtils.closeQuietly(jis); } } @WebRemote @Restrict("#{identity.loggedIn}") public void updateDependency(String uuid, String dependencyPath) { PackageItem item = getRulesRepository().loadPackageByUUID(uuid); item.updateDependency(dependencyPath); item.checkin("Update dependency"); } public String[] getDependencies(String uuid) { PackageItem item = getRulesRepository().loadPackageByUUID(uuid); return item.getDependencies(); } private JarInputStream typesForModel(List<String> res, AssetItem asset) throws IOException { JarInputStream jis; jis = new JarInputStream(asset.getBinaryContentAttachment()); JarEntry entry = null; while ((entry = jis.getNextJarEntry()) != null) { if (!entry.isDirectory()) { if (entry.getName().endsWith(".class")) { res.add(ModelContentHandler.convertPathToName(entry.getName())); } } } return jis; } private void typesForOthers(List<String> res, AssetItem asset) { // its delcared model DrlParser parser = new DrlParser(); try { PackageDescr desc = parser.parse(asset.getContent()); List<TypeDeclarationDescr> types = desc.getTypeDeclarations(); for (TypeDeclarationDescr typeDeclarationDescr : types) { res.add(typeDeclarationDescr.getTypeName()); } } catch (DroolsParserException e) { log.error("An error occurred parsing rule: " + e.getMessage()); } } @Restrict("#{identity.loggedIn}") public void installSampleRepository() throws SerializationException { getRulesRepository() .importRepository(this.getClass().getResourceAsStream("/mortgage-sample-repository.xml")); this.rebuildPackages(); this.rebuildSnapshots(); } /** * @deprecated in favour of {@link #compareSnapshots(SnapshotComparisonPageRequest)} */ public SnapshotDiffs compareSnapshots(String packageName, String firstSnapshotName, String secondSnapshotName) { return repositoryPackageOperations.compareSnapshots(packageName, firstSnapshotName, secondSnapshotName); } public SnapshotComparisonPageResponse compareSnapshots(SnapshotComparisonPageRequest request) { if (request == null) { throw new IllegalArgumentException("request cannot be null"); } if (request.getPageSize() != null && request.getPageSize() < 0) { throw new IllegalArgumentException("pageSize cannot be less than zero."); } return repositoryPackageOperations.compareSnapshots(request); } @WebRemote @Restrict("#{identity.loggedIn}") public SingleScenarioResult runScenario(String packageName, Scenario scenario) throws SerializationException { serviceSecurity.checkSecurityIsPackageDeveloperWithPackageName(packageName); return runScenario(packageName, scenario, null); } private SingleScenarioResult runScenario(String packageName, Scenario scenario, RuleCoverageListener coverage) throws SerializationException { PackageItem item = this.getRulesRepository().loadPackage(packageName); SingleScenarioResult result = null; // nasty classloader needed to make sure we use the same tree the whole // time. ClassLoader originalCL = Thread.currentThread().getContextClassLoader(); try { final RuleBase rb = loadCacheRuleBase(item); ClassLoader cl = ((InternalRuleBase) RuleBaseCache.getInstance().get(item.getUUID())) .getRootClassLoader(); Thread.currentThread().setContextClassLoader(cl); result = runScenario(scenario, item, cl, rb, coverage); } catch (Exception e) { if (e instanceof DetailedSerializationException) { DetailedSerializationException err = (DetailedSerializationException) e; result = new SingleScenarioResult(); if (err.getErrs() != null) { result.result = new ScenarioRunResult(err.getErrs(), null); } else { throw err; } } else { throw new DetailedSerializationException("Unable to run the scenario.", e.getMessage()); } } finally { Thread.currentThread().setContextClassLoader(originalCL); } return result; } /* * Set the Rule base in a cache */ private RuleBase loadCacheRuleBase(PackageItem packageItem) throws DetailedSerializationException { RuleBase rb = null; if (packageItem.isBinaryUpToDate() && RuleBaseCache.getInstance().contains(packageItem.getUUID())) { rb = RuleBaseCache.getInstance().get(packageItem.getUUID()); } else { // load up the classloader we are going to use ClassLoaderBuilder classLoaderBuilder = new ClassLoaderBuilder( packageItem.listAssetsWithVersionsSpecifiedByDependenciesByFormat(AssetFormats.MODEL)); ClassLoader buildCl = classLoaderBuilder.buildClassLoader(); // we have to build the package, and try again. if (packageItem.isBinaryUpToDate()) { rb = loadRuleBase(packageItem, buildCl); RuleBaseCache.getInstance().put(packageItem.getUUID(), rb); } else { BuilderResult result = repositoryPackageOperations.buildPackage(packageItem, false); if (result == null || result.getLines().size() == 0) { rb = loadRuleBase(packageItem, buildCl); RuleBaseCache.getInstance().put(packageItem.getUUID(), rb); } else throw new DetailedSerializationException("Build error", result.getLines()); } } return rb; } private RuleBase loadRuleBase(PackageItem item, ClassLoader cl) throws DetailedSerializationException { try { return deserKnowledgebase(item, cl); } catch (ClassNotFoundException e) { log.error("Unable to load rule base.", e); throw new DetailedSerializationException("A required class was not found.", e.getMessage()); } catch (Exception e) { log.error("Unable to load rule base.", e); log.info("...but trying to rebuild binaries..."); try { BuilderResult res = repositoryPackageOperations.buildPackage(item, true); if (res != null && res.getLines().size() > 0) { log.error("There were errors when rebuilding the knowledgebase."); throw new DetailedSerializationException("There were errors when rebuilding the knowledgebase.", ""); } } catch (Exception e1) { log.error("Unable to rebuild the rulebase: " + e.getMessage()); throw new DetailedSerializationException("Unable to rebuild the rulebase.", e.getMessage()); } try { return deserKnowledgebase(item, cl); } catch (Exception e2) { log.error("Unable to reload knowledgebase: " + e.getMessage()); throw new DetailedSerializationException("Unable to reload knowledgebase.", e.getMessage()); } } } private RuleBase deserKnowledgebase(PackageItem item, ClassLoader classloader) throws IOException, ClassNotFoundException { RuleBase rulebase = RuleBaseFactory.newRuleBase(new RuleBaseConfiguration(classloader)); Package bin = (Package) DroolsStreamUtils.streamIn(item.getCompiledPackageBytes(), classloader); rulebase.addPackage(bin); return rulebase; } private SingleScenarioResult runScenario(Scenario scenario, PackageItem item, ClassLoader cl, RuleBase rulebase, RuleCoverageListener coverage) throws DetailedSerializationException { Package bin = rulebase.getPackages()[0]; Set<String> imps = bin.getImports().keySet(); Set<String> allImps = new HashSet<String>(imps); if (bin.getGlobals() != null) { for (Object o : bin.getGlobals().keySet()) { allImps.add(bin.getGlobals().get(o)); } } allImps.add(bin.getName() + ".*"); // need this for Generated beans to // work ClassTypeResolver classTypeResolver = new ClassTypeResolver(allImps, cl); SessionConfiguration sessionConfiguration = new SessionConfiguration(); sessionConfiguration.setClockType(ClockType.PSEUDO_CLOCK); sessionConfiguration.setKeepReference(false); InternalWorkingMemory workingMemory = (InternalWorkingMemory) rulebase .newStatefulSession(sessionConfiguration, null); if (coverage != null) workingMemory.addEventListener(coverage); try { AuditLogReporter logger = new AuditLogReporter(workingMemory); new ScenarioRunner(scenario, classTypeResolver, workingMemory); SingleScenarioResult singleScenarioresult = new SingleScenarioResult(); singleScenarioresult.auditLog = logger.buildReport(); singleScenarioresult.result = new ScenarioRunResult(null, scenario); return singleScenarioresult; } catch (ClassNotFoundException e) { log.error("Unable to load a required class.", e); throw new DetailedSerializationException("Unable to load a required class.", e.getMessage()); } catch (ConsequenceException e) { String messageShort = "There was an error executing the consequence of rule [" + e.getRule().getName() + "]"; String messageLong = e.getMessage(); if (e.getCause() != null) { messageLong += "\nCAUSED BY " + e.getCause().getMessage(); } log.error(messageShort + ": " + messageLong, e); throw new DetailedSerializationException(messageShort, messageLong); } catch (Exception e) { log.error("Unable to run the scenario.", e); throw new DetailedSerializationException("Unable to run the scenario.", e.getMessage()); } } @WebRemote @Restrict("#{identity.loggedIn}") public BulkTestRunResult runScenariosInPackage(String packageUUID) throws SerializationException { serviceSecurity.checkSecurityIsPackageDeveloperWithPackageUuid(packageUUID); PackageItem item = getRulesRepository().loadPackageByUUID(packageUUID); return runScenariosInPackage(item); } public BulkTestRunResult runScenariosInPackage(PackageItem packageItem) throws DetailedSerializationException, SerializationException { ClassLoader originalClassloader = Thread.currentThread().getContextClassLoader(); ClassLoader classloader = null; try { if (packageItem.isBinaryUpToDate() && RuleBaseCache.getInstance().contains(packageItem.getUUID())) { AbstractRuleBase arb = (AbstractRuleBase) RuleBaseCache.getInstance().get(packageItem.getUUID()); // load up the existing class loader from before classloader = arb.getConfiguration().getClassLoader(); Thread.currentThread().setContextClassLoader(classloader); } else { // load up the classloader we are going to use ClassLoaderBuilder classLoaderBuilder = new ClassLoaderBuilder( packageItem.listAssetsWithVersionsSpecifiedByDependenciesByFormat(AssetFormats.MODEL)); classloader = classLoaderBuilder.buildClassLoader(); Thread.currentThread().setContextClassLoader(classloader); // we have to build the package, and try again. if (packageItem.isBinaryUpToDate()) { RuleBaseCache.getInstance().put(packageItem.getUUID(), loadRuleBase(packageItem, classloader)); } else { BuilderResult result = repositoryPackageOperations.buildPackage(packageItem, false); if (result == null || result.getLines().size() == 0) { RuleBaseCache.getInstance().put(packageItem.getUUID(), loadRuleBase(packageItem, classloader)); } else { return new BulkTestRunResult(result, null, 0, null); } } } AssetItemIterator it = packageItem.listAssetsByFormat(AssetFormats.TEST_SCENARIO); List<ScenarioResultSummary> resultSummaries = new ArrayList<ScenarioResultSummary>(); RuleBase rb = RuleBaseCache.getInstance().get(packageItem.getUUID()); Package bin = rb.getPackages()[0]; RuleCoverageListener coverage = new RuleCoverageListener(expectedRules(bin)); while (it.hasNext()) { AssetItem as = it.next(); if (!as.getDisabled()) { RuleAsset asset = repositoryAssetOperations.loadAsset(as); Scenario sc = (Scenario) asset.getContent(); runScenario(packageItem.getName(), sc, coverage);// runScenario(sc, res, // workingMemory).scenario; int[] totals = sc.countFailuresTotal(); resultSummaries.add(new ScenarioResultSummary(totals[0], totals[1], asset.getName(), asset.getDescription(), asset.getUuid())); } } ScenarioResultSummary[] summaries = resultSummaries .toArray(new ScenarioResultSummary[resultSummaries.size()]); return new BulkTestRunResult(null, resultSummaries.toArray(summaries), coverage.getPercentCovered(), coverage.getUnfiredRules()); } finally { Thread.currentThread().setContextClassLoader(originalClassloader); } } private HashSet<String> expectedRules(Package bin) { HashSet<String> h = new HashSet<String>(); for (int i = 0; i < bin.getRules().length; i++) { h.add(bin.getRules()[i].getName()); } return h; } }