From 2f855591dea0eb5ffbcce490dd7a7eb9c2f00a23 Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Thu, 3 Apr 2014 08:44:17 +0200 Subject: ResourceImportHandler interface to allow custom types or override the structure of standard ones. Specify with ResourceImportHandler. c2kprop. DefaultResourceImportHandler is used if not defined, which handled the 5 standard types (CA,EA,OD,SC,SM). Fixes #178 Conflicts: src/main/java/com/c2kernel/process/Bootstrap.java src/main/java/com/c2kernel/process/module/Module.java --- .../predefined/entitycreation/NewAgent.java | 5 - .../predefined/entitycreation/NewItem.java | 6 - .../predefined/entitycreation/NewRole.java | 5 - src/main/java/com/c2kernel/process/Bootstrap.java | 161 ++++++++++++--------- .../java/com/c2kernel/process/module/Module.java | 12 +- .../com/c2kernel/process/module/ModuleImport.java | 5 +- .../c2kernel/process/module/ModuleResource.java | 13 -- .../resource/DefaultResourceImportHandler.java | 88 +++++++++++ .../process/resource/ResourceImportHandler.java | 47 ++++++ 9 files changed, 240 insertions(+), 102 deletions(-) create mode 100644 src/main/java/com/c2kernel/process/resource/DefaultResourceImportHandler.java create mode 100644 src/main/java/com/c2kernel/process/resource/ResourceImportHandler.java diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewAgent.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewAgent.java index e7301a1..0b60f80 100644 --- a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewAgent.java +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewAgent.java @@ -57,9 +57,4 @@ public class NewAgent extends ModuleImport implements java.io.Serializable { } } - - @Override - public String getPath(String ns) { - return null; - } } diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewItem.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewItem.java index ed6fd20..0e690be 100644 --- a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewItem.java +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewItem.java @@ -188,10 +188,4 @@ public class NewItem extends ModuleImport { } } } - - @Override - public String getPath(String ns) { - setNamespace(ns); - return initialPath; - } } diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewRole.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewRole.java index 1800b0e..003b7f7 100644 --- a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewRole.java +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewRole.java @@ -11,11 +11,6 @@ public class NewRole extends ModuleImport { public NewRole() { } - - @Override - public String getPath(String ns) { - return null; // roles don't have user-specified domain paths - } public void create(int agentId) throws ObjectAlreadyExistsException, ObjectCannotBeUpdated { Gateway.getLDAPLookup().getRoleManager().createRole(name, jobList); diff --git a/src/main/java/com/c2kernel/process/Bootstrap.java b/src/main/java/com/c2kernel/process/Bootstrap.java index 08cf2e7..4af01aa 100644 --- a/src/main/java/com/c2kernel/process/Bootstrap.java +++ b/src/main/java/com/c2kernel/process/Bootstrap.java @@ -2,6 +2,8 @@ package com.c2kernel.process; import java.net.InetAddress; import java.util.Enumeration; +import java.util.HashMap; +import java.util.Set; import java.util.StringTokenizer; import org.custommonkey.xmlunit.Diff; @@ -28,6 +30,8 @@ import com.c2kernel.lookup.RolePath; import com.c2kernel.persistency.ClusterStorage; import com.c2kernel.persistency.outcome.Outcome; import com.c2kernel.persistency.outcome.Viewpoint; +import com.c2kernel.process.resource.DefaultResourceImportHandler; +import com.c2kernel.process.resource.ResourceImportHandler; import com.c2kernel.property.Property; import com.c2kernel.property.PropertyArrayList; import com.c2kernel.property.PropertyDescription; @@ -45,6 +49,7 @@ import com.c2kernel.utils.Resource; public class Bootstrap { static DomainPath thisServerPath; + static HashMap resHandlerCache = new HashMap(); /** * Run everything without timing-out the service wrapper @@ -100,10 +105,8 @@ public class Bootstrap String itemType = thisItem.substring(0,delim); String itemName = thisItem.substring(delim+1); try { - String data = Resource.getTextResource(ns, "boot/"+thisItem+(itemType.equals("OD")?".xsd":".xml")); - if (data == null) - Logger.die("No data found for "+getDataType(itemType)+" "+itemName); - verifyResource(ns, itemName, 0, itemType, data, reset); + String location = "boot/"+thisItem+(itemType.equals("OD")?".xsd":".xml"); + verifyResource(ns, itemName, 0, itemType, location, reset); } catch (Exception e) { Logger.error(e); Logger.die("Error importing bootstrap items. Unsafe to continue."); @@ -112,64 +115,120 @@ public class Bootstrap } - public static void verifyResource(String ns, String itemName, Integer version, String itemType, String data, boolean reset) throws Exception { + public static DomainPath verifyResource(String ns, String itemName, Integer version, String itemType, String dataLocation, boolean reset) throws Exception { if (version == null) version = 0; - Logger.msg(1, "Bootstrap.verifyResource() - Verifying version "+version+" of "+getDataType(itemType)+" "+itemName); + ResourceImportHandler typeImpHandler = getHandler(itemType); + Logger.msg(1, "Bootstrap.verifyResource() - Verifying version "+version+" of "+typeImpHandler.getName()+" "+itemName); - Enumeration en = Gateway.getLDAPLookup().search(getTypeRoot(itemType), itemName); + // Find or create Item for Resource + DomainPath modDomPath = typeImpHandler.getPath(itemName, ns); ItemProxy thisProxy; - Outcome newOutcome = new Outcome(0, data, getDataType(itemType), 0); - + Enumeration en = Gateway.getLDAPLookup().search(typeImpHandler.getTypeRoot(), itemName); if (!en.hasMoreElements()) { - Logger.msg("Bootstrap.verifyResource() - "+getDataType(itemType)+" "+itemName+" not found. Creating new."); - thisProxy = createResourceItem(itemType, itemName, ns); + Logger.msg("Bootstrap.verifyResource() - "+typeImpHandler.getName()+" "+itemName+" not found. Creating new."); + thisProxy = createResourceItem(typeImpHandler, itemName, ns); } else { DomainPath path = (DomainPath)en.nextElement(); thisProxy = (ItemProxy)Gateway.getProxyManager().getProxy(path); - try { - Viewpoint currentData = (Viewpoint)thisProxy.getObject(ClusterStorage.VIEWPOINT+"/"+getDataType(itemType)+"/"+version); + + // Verify module property and location + + String moduleName = (ns==null?"kernel":ns); + String itemModule; + try{ + itemModule = thisProxy.getProperty("Module"); + if (!itemModule.equals("") && !itemModule.equals("null") && !moduleName.equals(itemModule)) { + Logger.error("Bootstrap.verifyResource() - Module clash! Resource '"+itemName+"' included in module "+moduleName+" but is assigned to '"+itemModule+"'. Not overwriting."); + return path; + } + } catch (ObjectNotFoundException ex) { + itemModule = ""; + } + + if (!moduleName.equals(itemModule)) { // write module property + Gateway.getStorage().put(thisProxy.getSystemKey(), new Property("Module", moduleName), thisProxy); + } + + if (!modDomPath.equals(path)) { // move item to module subtree + Logger.msg("Module item "+itemName+" found with path "+path.toString()+". Moving to "+modDomPath.toString()); + modDomPath.setEntity(new EntityPath(thisProxy.getSystemKey())); + if (!modDomPath.exists()) + Gateway.getLDAPLookup().add(modDomPath); + Gateway.getLDAPLookup().delete(path); + } + } + + // Verify/Import Outcomes, creating events and views as necessary + Set impList = typeImpHandler.getResourceOutcomes(itemName, ns, dataLocation, version); + for (Outcome newOutcome : impList) { + try { + Viewpoint currentData = (Viewpoint)thisProxy.getObject(ClusterStorage.VIEWPOINT+"/"+newOutcome.getSchemaType()+"/"+version); Outcome oldData = currentData.getOutcome(); XMLUnit.setIgnoreWhitespace(true); XMLUnit.setIgnoreComments(true); Diff xmlDiff = new Diff(newOutcome.getDOM(), oldData.getDOM()); if (xmlDiff.identical()) { Logger.msg(5, "Bootstrap.verifyResource() - Data identical, no update required"); - return; + continue; } else { Logger.msg("Difference found in "+itemName+": "+xmlDiff.toString()); if (!reset && !currentData.getEvent().getStepPath().equals("Bootstrap")) { Logger.msg("Version "+version+" was not set by Bootstrap, and reset not requested. Not overwriting."); - return; + continue; } } } catch (ObjectNotFoundException ex) { - Logger.error("Bootstrap.verifyResource() - Item "+itemName+" exists but version "+version+" not found! Attempting to insert new."); + Logger.msg("Bootstrap.verifyResource() - Item "+itemName+" exists but version "+version+" not found! Attempting to insert new."); } + // data was missing or doesn't match + Logger.msg("Bootstrap.verifyResource() - Writing new version "+version+" to "+newOutcome.getSchemaType()+" "+itemName); + History hist = new History(thisProxy.getSystemKey(), thisProxy); + Event newEvent = hist.addEvent("system", "Admin", Transitions.DONE, "Bootstrap", "Bootstrap", "Bootstrap", newOutcome.getSchemaType(), 0, String.valueOf(version), States.FINISHED); + newOutcome.setID(newEvent.getID()); + Viewpoint newLastView = new Viewpoint(thisProxy.getSystemKey(), newOutcome.getSchemaType(), "last", 0, newEvent.getID()); + Viewpoint newNumberView = new Viewpoint(thisProxy.getSystemKey(), newOutcome.getSchemaType(), String.valueOf(version), 0, newEvent.getID()); + Gateway.getStorage().put(thisProxy.getSystemKey(), newOutcome, thisProxy); + Gateway.getStorage().put(thisProxy.getSystemKey(), newLastView, thisProxy); + Gateway.getStorage().put(thisProxy.getSystemKey(), newNumberView, thisProxy); } - // data was missing or doesn't match - Logger.msg("Bootstrap.verifyResource() - Writing new version "+version+" to "+getDataType(itemType)+" "+itemName); - History hist = new History(thisProxy.getSystemKey(), thisProxy); - Event newEvent = hist.addEvent("system", "Admin", Transitions.DONE, "Bootstrap", "Bootstrap", "Bootstrap", getDataType(itemType), 0, String.valueOf(version), States.FINISHED); - newOutcome.setID(newEvent.getID()); - Viewpoint newLastView = new Viewpoint(thisProxy.getSystemKey(), getDataType(itemType), "last", 0, newEvent.getID()); - Viewpoint newZeroView = new Viewpoint(thisProxy.getSystemKey(), getDataType(itemType), String.valueOf(version), 0, newEvent.getID()); - Gateway.getStorage().put(thisProxy.getSystemKey(), newOutcome, thisProxy); - Gateway.getStorage().put(thisProxy.getSystemKey(), newLastView, thisProxy); - Gateway.getStorage().put(thisProxy.getSystemKey(), newZeroView, thisProxy); - Gateway.getStorage().commit(thisProxy); + Gateway.getStorage().commit(thisProxy); + return modDomPath; } - /** + private static ResourceImportHandler getHandler(String resType) throws Exception { + if (resHandlerCache.containsKey(resType)) + return resHandlerCache.get(resType); + ResourceImportHandler handler; + String handlerProp = Gateway.getProperty("ResourceImportHandler."+resType); + if (handlerProp != null && handlerProp.length()!=0) { + try { + Class handlerClass = Class.forName(handlerProp); + handler = (ResourceImportHandler) handlerClass.newInstance(); + } catch (ClassNotFoundException e) { + throw new Exception("Handler class "+handlerProp+" for importing "+resType+" resources not found"); + } catch (ClassCastException e) { + throw new Exception(handlerProp+" for importing "+resType+" was not a ResourceImportHandler"); + } + } + else + handler = new DefaultResourceImportHandler(resType); + + resHandlerCache.put(resType, handler); + return handler; + } + + /** * @param itemType * @param itemName * @param data */ - private static ItemProxy createResourceItem(String itemType, String itemName, String ns) throws Exception { - // create props - PropertyDescriptionList pdList = (PropertyDescriptionList)Gateway.getMarshaller().unmarshall(Resource.getTextResource(null, "boot/property/"+itemType+"Prop.xml")); + private static ItemProxy createResourceItem(ResourceImportHandler impHandler, String itemName, String ns) throws Exception { + + // create props + PropertyDescriptionList pdList = impHandler.getPropDesc(); PropertyArrayList props = new PropertyArrayList(); for (int i = 0; i < pdList.list.size(); i++) { PropertyDescription pd = pdList.list.get(i); @@ -178,16 +237,11 @@ public class Bootstrap props.list.add(new Property(propName, propVal)); } - CompositeActivity ca = new CompositeActivity(); - if (ns!=null && Gateway.getProperty("Module.debug", "false").equals("true")) { - String wf; - if (itemType.equals("CA")) wf = "ManageCompositeActDef"; - else if (itemType.equals("EA")) wf = "ManageElementaryActDef"; - else if (itemType.equals("OD")) wf = "ManageSchema"; - else if (itemType.equals("SC")) wf = "ManageScript"; - else throw new Exception("Unknown bootstrap item type: "+itemType); - ca = (CompositeActivity) ((CompositeActivityDef)LocalObjectLoader.getActDef(wf, "last")).instantiate(); - } + CompositeActivity ca; + if (ns!=null && "true".equals(Gateway.getProperty("Module.debug"))) + ca = (CompositeActivity) ((CompositeActivityDef)LocalObjectLoader.getActDef(impHandler.getWorkflowName(), "0")).instantiate(); + else + ca = new CompositeActivity(); EntityPath entityPath = Gateway.getLDAPLookup().getNextKeyManager().generateNextEntityKey(); TraceableEntity newItem = (TraceableEntity)Gateway.getCorbaServer().createEntity(entityPath); @@ -196,35 +250,12 @@ public class Bootstrap 1, Gateway.getMarshaller().marshall(props), Gateway.getMarshaller().marshall(ca)); - DomainPath newDomPath = new DomainPath(getTypeRoot(itemType).toString()+"/system/"+(ns==null?"kernel":ns)+"/"+itemName); + DomainPath newDomPath = impHandler.getPath(itemName, ns); newDomPath.setEntity(entityPath); Gateway.getLDAPLookup().add(newDomPath); return (ItemProxy)Gateway.getProxyManager().getProxy(entityPath); } - public static DomainPath getTypeRoot(String type) throws Exception { - if (type.equals("CA") || type.equals("EA")) - return new DomainPath("/desc/ActivityDesc/"); - if (type.equals("SC")) - return new DomainPath("/desc/Script/"); - if (type.equals("OD")) - return new DomainPath("/desc/OutcomeDesc/"); - throw new Exception("Unknown bootstrap item type: "+type); - } - - private static String getDataType(String type) throws Exception { - if (type.equals("CA")) - return "CompositeActivityDef"; - if (type.equals("EA")) - return "ElementaryActivityDef"; - if (type.equals("OD")) - return "Schema"; - if (type.equals("SC")) - return "Script"; - throw new Exception("Unknown bootstrap item type: "+type); - - } - /************************************************************************** * Checks for the existence of the admin users so you can use Cristal **************************************************************************/ diff --git a/src/main/java/com/c2kernel/process/module/Module.java b/src/main/java/com/c2kernel/process/module/Module.java index 13d2e68..eb3c614 100644 --- a/src/main/java/com/c2kernel/process/module/Module.java +++ b/src/main/java/com/c2kernel/process/module/Module.java @@ -11,13 +11,13 @@ import com.c2kernel.lifecycle.instance.predefined.entitycreation.NewAgent; import com.c2kernel.lifecycle.instance.predefined.entitycreation.NewItem; import com.c2kernel.lifecycle.instance.predefined.entitycreation.NewRole; import com.c2kernel.lifecycle.instance.predefined.entitycreation.Outcome; +import com.c2kernel.lookup.DomainPath; import com.c2kernel.lookup.RolePath; import com.c2kernel.process.Bootstrap; import com.c2kernel.process.Gateway; import com.c2kernel.scripting.ErrorInfo; import com.c2kernel.scripting.ScriptingEngineException; import com.c2kernel.utils.Logger; -import com.c2kernel.utils.Resource; public class Module { @@ -60,10 +60,9 @@ public class Module { // Add dependency for all children Dependency children = new Dependency("Contents"); for (ModuleImport thisImport : imports.list) { - String path = thisImport.getPath(ns); + DomainPath path = thisImport.path; if (path != null) - children.dependencyMemberList.add( - new DependencyMember(path+"/"+thisImport.name)); + children.dependencyMemberList.add(new DependencyMember(path.toString())); } moduleItem.dependencyList.add(children); // Add moduleXML @@ -79,7 +78,8 @@ public class Module { for (ModuleResource thisRes : imports.getResources()) { try { - Bootstrap.verifyResource(ns, thisRes.name, thisRes.version, thisRes.resourceType, Resource.getTextResource(ns, thisRes.resourceLocation), reset); + thisRes.path = Bootstrap.verifyResource(ns, thisRes.name, thisRes.version, + thisRes.resourceType, thisRes.resourceLocation, reset); } catch (Exception ex) { Logger.error(ex); } @@ -152,4 +152,4 @@ public class Module { public boolean hasDependency(String dep) { return info.dependency.contains(dep); } -} \ No newline at end of file +} diff --git a/src/main/java/com/c2kernel/process/module/ModuleImport.java b/src/main/java/com/c2kernel/process/module/ModuleImport.java index 77bf3f6..1f5b16d 100644 --- a/src/main/java/com/c2kernel/process/module/ModuleImport.java +++ b/src/main/java/com/c2kernel/process/module/ModuleImport.java @@ -1,9 +1,10 @@ package com.c2kernel.process.module; +import com.c2kernel.lookup.DomainPath; + public abstract class ModuleImport { public String name; + public DomainPath path; - public abstract String getPath(String ns); - } \ No newline at end of file diff --git a/src/main/java/com/c2kernel/process/module/ModuleResource.java b/src/main/java/com/c2kernel/process/module/ModuleResource.java index 2f7b638..b36623f 100644 --- a/src/main/java/com/c2kernel/process/module/ModuleResource.java +++ b/src/main/java/com/c2kernel/process/module/ModuleResource.java @@ -8,17 +8,4 @@ public class ModuleResource extends ModuleImport { public ModuleResource() { } - - @Override - public String getPath(String ns) { - StringBuffer path = new StringBuffer(); - if (resourceType.equals("CA") || resourceType.equals("EA")) - path.append("/desc/ActivityDesc/"); - if (resourceType.equals("SC")) - path.append("/desc/Script/"); - if (resourceType.equals("OD")) - path.append("/desc/OutcomeDesc/"); - path.append("system/").append(ns==null?"kernel":ns); - return path.toString(); - } } \ No newline at end of file diff --git a/src/main/java/com/c2kernel/process/resource/DefaultResourceImportHandler.java b/src/main/java/com/c2kernel/process/resource/DefaultResourceImportHandler.java new file mode 100644 index 0000000..3b3abfc --- /dev/null +++ b/src/main/java/com/c2kernel/process/resource/DefaultResourceImportHandler.java @@ -0,0 +1,88 @@ +package com.c2kernel.process.resource; + +import java.util.HashSet; +import java.util.Set; + +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.PropertyDescriptionList; +import com.c2kernel.utils.Resource; + +public class DefaultResourceImportHandler implements ResourceImportHandler { + + String resType; + String schemaName; + String typeRoot; + DomainPath typeRootPath; + String wfDef; + PropertyDescriptionList props; + + public DefaultResourceImportHandler(String resType) throws Exception { + this.resType = resType; + if (resType.equals("CA")) { + wfDef = "ManageCompositeActDef"; + schemaName = "CompositeActivityDef"; + typeRoot = "/desc/ActivityDesc"; + } + else if (resType.equals("EA")) { + wfDef = "ManageElementaryActDef"; + schemaName = "ElementaryActivityDef"; + typeRoot = "/desc/ActivityDesc"; + } + else if (resType.equals("OD")) { + wfDef = "ManageSchema"; + schemaName = "Schema"; + typeRoot = "/desc/OutcomeDesc"; + } + else if (resType.equals("SC")) { + wfDef = "ManageScript"; + schemaName = "Script"; + typeRoot = "/desc/Script"; + } + else if (resType.equals("SM")) { + wfDef = "ManageStateMachine"; + schemaName = "StateMachine"; + typeRoot = "/desc/StateMachine"; + } + else throw new Exception("Unknown bootstrap item type: "+resType); + typeRootPath = new DomainPath(typeRoot); + props = (PropertyDescriptionList)Gateway.getMarshaller().unmarshall(Resource.getTextResource(null, "boot/property/"+resType+"Prop.xml")); + } + + @Override + public DomainPath getTypeRoot() { + return typeRootPath; + } + + @Override + public String getName() { + return schemaName; + } + + @Override + public DomainPath getPath(String name, String ns) throws Exception { + return new DomainPath(typeRoot+"/system/"+(ns==null?"kernel":ns)+'/'+name); + } + + @Override + public Set getResourceOutcomes(String name, String ns, String location, int version) throws Exception { + HashSet retArr = new HashSet(); + String data = Resource.getTextResource(ns, location); + if (data == null) + throw new Exception("No data found for "+schemaName+" "+name); + Outcome resOutcome = new Outcome(0, data, schemaName, 0); + retArr.add(resOutcome); + return retArr; + } + + @Override + public PropertyDescriptionList getPropDesc() throws Exception { + return props; + } + + @Override + public String getWorkflowName() throws Exception { + return wfDef; + } +} diff --git a/src/main/java/com/c2kernel/process/resource/ResourceImportHandler.java b/src/main/java/com/c2kernel/process/resource/ResourceImportHandler.java new file mode 100644 index 0000000..8f825b5 --- /dev/null +++ b/src/main/java/com/c2kernel/process/resource/ResourceImportHandler.java @@ -0,0 +1,47 @@ +package com.c2kernel.process.resource; + +import java.util.Set; + +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.property.PropertyDescriptionList; + +public interface ResourceImportHandler { + + + /** Returns the DomainPath for a specific resource + * @param ns - module namespace + * @param name - resource name + * @return + */ + public DomainPath getPath(String name, String ns) throws Exception; + + /** Generates the outcomes that the resource should contain. + * @param res - the module resource definition + * @return a set of outcomes to be synced with the resource item. + * @throws Exception - if the supplied resources are not valid + */ + public Set getResourceOutcomes(String name, String ns, String location, int version) throws Exception; + + /** Gives the CompActDef name to instantiate to provide the workflow for this type of resource. + * Should be found in the CA typeroot (/desc/ActivityDesc/) + * @return String workflow name + * @throws Exception + */ + public String getWorkflowName() throws Exception; + + /** Should return all of the Properties the resource Item + * will have on creation. The Property 'Name' will be created and populated automatically, even if not declared. + * @return a PropertyDescriptionList - an arraylist of PropertyDescriptions + * @throws Exception + */ + public PropertyDescriptionList getPropDesc() throws Exception; + + /** The directory context to search for existing resources. The name of the resource must be unique below this point. + * @return Root path + */ + public DomainPath getTypeRoot(); + + public String getName(); + +} -- cgit v1.2.3