Author: mic...@jb... Date: 2006-01-18 06:33:40 -0500 (Wed, 18 Jan 2006) New Revision: 2131 Added: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryManagerImpl.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/ISaveHistory.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/IVersionable.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/Persistent.java Removed: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ISaveHistory.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/IVersionable.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/Persistent.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/RepositoryImpl.java Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ApplicationDataDef.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/FunctionDef.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ImportDef.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryException.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryFactory.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryManager.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleDef.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetAttachment.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetDef.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetVersionInfo.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/Tag.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/HibernateUtil.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/RepoProxyHandler.java trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/StoreEventListener.java trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleDef.hbm.xml trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleSetAttachment.hbm.xml trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleSetDef.hbm.xml trunk/labs/jbossrules/drools-repository/src/test/java/org/drools/repository/AttachmentPersistTest.java trunk/labs/jbossrules/drools-repository/src/test/java/org/drools/repository/IntegrationTest.java trunk/labs/jbossrules/drools-repository/src/test/java/org/drools/repository/RulePersistenceTest.java trunk/labs/jbossrules/drools-repository/src/test/java/org/drools/repository/RuleSetPersistenceTest.java trunk/labs/jbossrules/drools-repository/src/test/resources/drools-repository-db.cfg.xml Log: lots of improvements around versioning, major refactoring Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ApplicationDataDef.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ApplicationDataDef.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ApplicationDataDef.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -1,5 +1,8 @@ package org.drools.repository; +import org.drools.repository.db.IVersionable; +import org.drools.repository.db.Persistent; + /** * Application data contains a definition of objects that may be provided to the * rule engine to support the execution of rules. Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/FunctionDef.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/FunctionDef.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/FunctionDef.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -1,5 +1,8 @@ package org.drools.repository; +import org.drools.repository.db.IVersionable; +import org.drools.repository.db.Persistent; + /** * A FunctionDef contains the definition of a function that is used in one or more rules. * Functions can be written in any language that is supported by the semantic framework. Deleted: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ISaveHistory.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ISaveHistory.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ISaveHistory.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -1,29 +0,0 @@ -package org.drools.repository; - -/** - * Assets that implement this will have their history saved. - * Is partly a marker interface for persistence. - */ -public interface ISaveHistory extends IVersionable { - - /** - * This indicates the ID the the original asset was saved with. Allows - * a history list to be queried. - */ - Long getHistoricalId(); - void setHistoricalId(Long id); - - /** - * @return True is the object is actually a save history record. - */ - boolean isHistoricalRecord(); - void setHistoricalRecord(boolean b); - - /** - * - * @param oldObject Previous version of the object of this type. - * @return - */ - boolean isStateChanged(ISaveHistory oldObject); - -} Deleted: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/IVersionable.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/IVersionable.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/IVersionable.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -1,39 +0,0 @@ -package org.drools.repository; - -/** - * All assets that support versioning must implement this. - * Versioning in this sense is "major" versioning, at the ruleset level. - * - * This is different to Save History versioning, which is implicit on save. - * - */ -public interface IVersionable { - - /** - * This is used to indicate that the asset is un-attached to - * any ruleset. Basically deleted. - * TODO: enhance this to delete if no longer needed. - */ - public static final long NO_VERSION = -1; - - /** of course they have to have an id ! - * Ids are always assigned by the database. - */ - Long getId(); - - /** Must create a fresh copy OF THE SAME TYPE, with a null Id */ - IVersionable copy(); - - /** - * The version number is used to group assets together in a RuleSet for instance - * The version number should ONLY be set by the repository, NOT by users. - */ - void setVersionNumber(long versionNumber); - - /** The version comment is used when major versions are created */ - void setVersionComment(String comment); - - String getVersionComment(); - - long getVersionNumber(); -} Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ImportDef.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ImportDef.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/ImportDef.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -1,5 +1,8 @@ package org.drools.repository; +import org.drools.repository.db.IVersionable; +import org.drools.repository.db.Persistent; + /** * This holds a type import for a ruleset. * TODO: This probably does not need to be versioned this granular. Deleted: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/Persistent.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/Persistent.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/Persistent.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -1,18 +0,0 @@ -package org.drools.repository; - -import java.io.Serializable; - -public class Persistent implements Serializable { - - private Long id; - - public Long getId(){ - return id; - } - - private void setId(Long id){ - this.id = id; - } - - -} Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryException.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryException.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryException.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -1,11 +1,22 @@ package org.drools.repository; /** + * This may be thrown by the repository if certain rules of access are broken. + * Generally this will roll back any transactions in progress. * + * Mostly it will contain a validation message which may be displayed. + * + * The repository instance should remain valid, however. + * + * If any other exceptions are thrown, however, the repository manager instance will be + * invalid. + * * @author <a href="mailto:mic...@gm..."> Michael Neale</a> */ public class RepositoryException extends RuntimeException { + private static final long serialVersionUID = 6720400703993720887L; + public RepositoryException(String message) { super(message); } Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryFactory.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryFactory.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryFactory.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -4,6 +4,7 @@ import org.drools.repository.db.RepoProxyHandler; + /** * This factory class provides instances of the repository in various flavours. * Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryManager.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryManager.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryManager.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -9,6 +9,10 @@ * This interface defines all the operations that cane be performed on the repository. * A client using this must be able to have a connection to the repository. * + * If RepositoryException is thrown, this usually means a validation error, a repository + * rule violation etc. For other exceptions, the repository manager instance may become invalid. + * If it is a stateful Repository, then it will need to be created from the factory fresh. + * * @author <a href="mailto:mic...@gm..."> Michael Neale</a> */ public interface RepositoryManager { @@ -19,8 +23,11 @@ */ public abstract void save(RuleDef newRule); + /** + * Load a rule based on a workingVersionNumber. + */ public abstract RuleDef loadRule(String ruleName, - long versionNumber); + long workingVersionNumber); /** * This will return a list of rules of "major versions" - these are rules that have been @@ -28,6 +35,13 @@ */ public abstract List listRuleVersions(String ruleName); + /** + * Find and return all the historical versions of a rule. + * Historcal versions are previous versions of the rules stored when + * a change to the rule was saved. + * + * This is distinct from Versions which are related to RuleSet versioning. += */ public abstract List listRuleSaveHistory(RuleDef rule); public abstract List findRulesByTag(String tag); @@ -47,7 +61,10 @@ public abstract RuleSetDef loadRuleSet(String ruleSetName, long workingVersionNumber); - public abstract RuleSetAttachment loadAttachment(String name); + /** + * Load an attachment with the appropriate version number. + */ + public abstract RuleSetAttachment loadAttachment(String name, long workingVersionNumber); public abstract void save(RuleSetAttachment attachment); @@ -64,7 +81,26 @@ String tag); - /** This is only required for stateful Repository session. It will be ignored for stateless ones */ + /** + * This will check out a rule for the given user id. + * This can be used to enforce "locking" of rule edits. + * + * This will save the rule as it stands, including any changes. + */ + public abstract void checkOutRule(RuleDef rule, String userId); + + /** + * This removes the check out flag. + * + * The userId must be supplied to confirm that the correct user + * is checking it in, an exception will be thrown if this is not correct. + * + * This can effectively be "overridden" by either just saving the rule, or passing + * in the correct username. It is up to client applications to enforce this behaviour. + */ + public abstract void checkInRule(RuleDef rule, String userId); + + /** This is only required for stateful Repository session. It will be ignored for stateless ones. */ public abstract void close(); } \ No newline at end of file Added: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryManagerImpl.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryManagerImpl.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryManagerImpl.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -0,0 +1,221 @@ +package org.drools.repository; + +import java.util.List; + + +import org.hibernate.Session; + +/** + * The repository manager takes care of storing and sychronising the repository + * data with the repository database, using hibernate. + * + * This should not be access directly, but via a proxy to configure the session correctly. + * + * Use RepositoryFactory to get an instance of a repository manager. + * + * @author <a href ="mailto:suj...@co..."> Sujit Pal</a> + * @author <a href="mailto:mic...@gm..."> Michael Neale</a> + */ +public class RepositoryManagerImpl + implements + RepositoryManager { + + private Session session; + + /** + * Session is injected by the proxy. + */ + public void injectSession(Session session) { + this.session = session; + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#save(org.drools.repository.RuleDef) + */ + public void save(RuleDef newRule) { + session.saveOrUpdate( newRule ); + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#loadRule(java.lang.String, long) + */ + public RuleDef loadRule(String ruleName, + long versionNumber) { + RuleDef result = (RuleDef) session.createQuery( "from RuleDef where name = :name and versionNumber = :version" ) + .setString( "name", ruleName ) + .setLong( "version", versionNumber ) + .uniqueResult(); + + return result; + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#listRuleVersions(java.lang.String) + */ + public List listRuleVersions(String ruleName) { + List result = (List) session.createQuery( "from RuleDef where name = :name order by versionNumber" ) + .setString( "name", ruleName ).list(); + return result; + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#listRuleSaveHistory(org.drools.repository.RuleDef) + */ + public List listRuleSaveHistory(RuleDef rule) { + disableHistoryFilter( session ); + + List result = (List) session.createQuery( "from RuleDef where historicalId = :id" ).setLong( "id", + rule.getId().longValue() ).list(); + + enableHistoryFilter( session ); + return result; + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#findRulesByTag(java.lang.String) + */ + public List findRulesByTag(String tag) { + List result = session.createQuery( "select rule from RuleDef as rule " + + "join rule.tags as tags " + + "where tags.tag = :tag" ).setString( "tag", tag ).list(); + return result; + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#save(org.drools.repository.RuleSetDef) + */ + public void save(RuleSetDef ruleSet) { + session.saveOrUpdate( ruleSet ); + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#loadRuleSet(java.lang.String, long) + */ + public RuleSetDef loadRuleSet(String ruleSetName, + long workingVersionNumber) { + session.clear(); //to make sure latest is loaded up, not stale + RuleSetDef def = loadRuleSetFiltered( ruleSetName, + workingVersionNumber ); + return def; + } + + /** + * This is put here for internal re-use. Internally the public methods should + * not be called. + */ + private RuleSetDef loadRuleSetFiltered(String ruleSetName, + long workingVersionNumber) { + enableWorkingVersionFilter( workingVersionNumber, + session ); + RuleSetDef def = loadRuleSetByName( ruleSetName, + session ); + def.setWorkingVersionNumber( workingVersionNumber ); + + disableWorkingVersionFilter( session ); + return def; + } + + private RuleSetDef loadRuleSetByName(String ruleSetName, + Session session) { + RuleSetDef def = (RuleSetDef) session.createQuery( "from RuleSetDef where name = :name" ).setString( "name", + ruleSetName ).uniqueResult(); + if (def == null) { + throw new RepositoryException("Unable to find RuleSet with name: [" + ruleSetName + "]"); + } + return def; + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#loadAttachment(java.lang.String) + */ + public RuleSetAttachment loadAttachment(String name, long workingVersionNumber) { + RuleSetAttachment at = (RuleSetAttachment) session.createQuery( "from RuleSetAttachment where name = :name and versionNumber = :versionNumber" ) + .setString( "name", name ) + .setLong( "versionNumber", workingVersionNumber) + .uniqueResult(); + return at; + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#save(org.drools.repository.RuleSetAttachment) + */ + public void save(RuleSetAttachment attachment) { + session.saveOrUpdate( attachment ); + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#listRuleSets() + */ + public List listRuleSets() { + List list = session.createQuery( "select distinct name from RuleSetDef where name is not null" ).list(); + return list; + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#delete(org.drools.repository.RuleDef) + */ + public void delete(RuleDef rule) { + session.delete( rule ); + } + + /* (non-Javadoc) + * @see org.drools.repository.db.RepositoryManager#searchRulesByTag(java.lang.String, java.lang.String) + */ + public List searchRulesByTag(String ruleSetName, + String tag) { + RuleSetDef def = loadRuleSetByName( ruleSetName, + session ); + List list = session.createFilter( def.getRules(), + "where this.tags.tag = :tag" ).setString( "tag", + tag ).list(); + + return list; + } + + public void checkOutRule(RuleDef rule, + String userId) { + rule.setCheckedOut(true); + rule.setCheckedOutBy(userId); + session.update(rule); + } + + public void checkInRule(RuleDef rule, String userId) { + if (!userId.equals(rule.getCheckedOutBy())) { + throw new RepositoryException("Unable to check in the rule, as it is currently checked out by " + rule.getCheckedOutBy()); + } + rule.setCheckedOut(false); + rule.setCheckedOutBy(null); + session.update(rule); + } + + public void close() { /*implemented by the proxy */} + + + ////////////////////////// + // Filters follow + ////////////////////////// + public void enableHistoryFilter(Session session) { + session.enableFilter( "historyFilter" ).setParameter( "viewHistory", + Boolean.FALSE ); + } + + void disableHistoryFilter(Session session) { + session.disableFilter( "historyFilter" ); + } + + void enableWorkingVersionFilter(long workingVersionNumber, + Session session) { + session.enableFilter( "workingVersionFilter" ).setParameter( "filteredVersionNumber", + new Long( workingVersionNumber ) ); + } + + void disableWorkingVersionFilter(Session session) { + session.disableFilter( "workingVersionFilter" ); + } + + + + + + +} Property changes on: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RepositoryManagerImpl.java ___________________________________________________________________ Name: svn:eol-style + native Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleDef.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleDef.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleDef.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -5,6 +5,10 @@ import java.util.Iterator; import java.util.Set; +import org.drools.repository.db.ISaveHistory; +import org.drools.repository.db.IVersionable; +import org.drools.repository.db.Persistent; + public class RuleDef extends Persistent implements ISaveHistory { @@ -25,7 +29,16 @@ private Date expiryDate; private Long historicalId; private boolean historicalRecord = false; + private int lockingVersion = 0; + + private int getLockingVersion() { + return lockingVersion; + } + private void setLockingVersion(int lockingVersion) { + this.lockingVersion = lockingVersion; + } + /** * Use tagging to aid with searching and sorting of large numbers of rules. */ @@ -44,13 +57,7 @@ } public void removeTag(String tagVal) { - for ( Iterator iter = this.tags.iterator(); iter.hasNext(); ) { - Tag tag = (Tag) iter.next(); - if (tag.getTag().equals(tagVal)) { - iter.remove(); - return; - } - } + Tag.removeTagFromCollection(tagVal, this.tags); } RuleDef() { @@ -100,7 +107,7 @@ return checkedOut; } - public void setCheckedOut(boolean checkedOut) { + void setCheckedOut(boolean checkedOut) { this.checkedOut = checkedOut; } @@ -108,7 +115,7 @@ return checkedOutBy; } - public void setCheckedOutBy(String checkOutBy) { + void setCheckedOutBy(String checkOutBy) { this.checkedOutBy = checkOutBy; } @@ -183,17 +190,8 @@ return tagList; } - /** - * Copy the tags. It is allowable to reuse the same Tag identities. - */ private Set copyTags() { - Set newTags = new HashSet(); - for ( Iterator iter = this.getTags().iterator(); iter.hasNext(); ) { - Tag tag = (Tag) iter.next(); - newTags.add( new Tag( tag.getTag() ) ); - - } - return newTags; + return Tag.copyTags(this.tags); } /** Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetAttachment.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetAttachment.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetAttachment.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -1,6 +1,12 @@ package org.drools.repository; +import java.util.HashSet; +import java.util.Set; +import org.drools.repository.db.IVersionable; +import org.drools.repository.db.Persistent; + + /** * A RuleSetAttachment may contain a ruleset that is stored in a non-normalised format. * An attachment may be a spreadsheet for instance. Or it may be a HTML document and a properties file. @@ -25,10 +31,18 @@ private String typeOfAttachment; private String name; - private long versionNumber = 1; + private long versionNumber; private String versionComment; + private Set tags; - + /** + * + * @param typeOfAttachment The type of the content, eg XLS, CSV, HTML. + * @param name The unique name of this attachment. Incorporate ruleset name if you like. + * @param content The data in byte[] form. If it is text, use UTF-8 encoding. + * @param originalFileName The original filename, if applicable. In some cases, people like + * to think of things in terms of files. Feel free to include the pathname. + */ public RuleSetAttachment(String typeOfAttachment, String name, byte[] content, @@ -38,12 +52,35 @@ this.name = name; this.content = content; this.originalFileName = originalFileName; - + this.versionNumber = 1; + this.versionComment = "new"; + this.tags = new HashSet(); } RuleSetAttachment() { } + /** + * Use tagging to aid with searching and sorting of large numbers of rules. + */ + public RuleSetAttachment addTag(String tag) { + this.tags.add( new Tag( tag ) ); + return this; + } + + public RuleSetAttachment addTag(Tag tag) { + this.tags.add( tag ); + return this; + } + + public void removeTag(Tag tag) { + this.tags.remove(tag); + } + + public void removeTag(String tagVal) { + Tag.removeTagFromCollection(tagVal, this.tags); + } + public String getName(){ return name; } @@ -90,6 +127,7 @@ this.getName(), this.getContent(), this.getOriginalFileName()); + copy.setTags(Tag.copyTags(this.tags)); return copy; } @@ -100,6 +138,14 @@ public String getVersionComment() { return this.versionComment; } + + public Set getTags() { + return tags; + } + + private void setTags(Set tags) { + this.tags = tags; + } Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetDef.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetDef.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetDef.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -1,9 +1,14 @@ package org.drools.repository; +import java.util.List; +import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import org.drools.repository.db.IVersionable; +import org.drools.repository.db.Persistent; + /** * The ruleset definition contains a grouping of rules for editing/release. The * workingVersionNumber drives what version of rules will be included in this @@ -53,7 +58,7 @@ this.applicationData = new HashSet(); this.imports = new HashSet(); this.workingVersionNumber = 1; - addNewVersionHistory("new", "created"); + addNewVersionHistory("new"); } /** @@ -277,11 +282,10 @@ * Ideally once a new version is created, the RuleSet should be stored and * then loaded fresh, which will hide the non working versions of the rules. */ - public void createNewVersion(String comment, - String newStatus) { + public void createNewVersion(String comment) { this.workingVersionNumber++; - addNewVersionHistory( newStatus, comment ); + addNewVersionHistory( comment ); createAndAddNewVersions( this.rules, comment, @@ -305,10 +309,9 @@ } - - private void addNewVersionHistory(String newStatus, String comment) { + + private void addNewVersionHistory( String comment) { RuleSetVersionInfo newVersion = new RuleSetVersionInfo(); - newVersion.setStatus( newStatus ); newVersion.setVersionNumber( this.workingVersionNumber ); newVersion.setVersionComment( comment ); this.versionHistory.add( newVersion ); Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetVersionInfo.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetVersionInfo.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/RuleSetVersionInfo.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -2,6 +2,8 @@ import java.util.Date; +import org.drools.repository.db.Persistent; + /** * This records information about a particular version of a ruleset. * Rulesets themselves are just a collection of rules. Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/Tag.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/Tag.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/Tag.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -1,6 +1,13 @@ package org.drools.repository; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import org.drools.repository.db.Persistent; + + /** * This represents a users tag for a rule, ruleset. * This aids with classification of rules in an ad-hoc fashion. @@ -32,15 +39,32 @@ return tag; } - public boolean equals(Object arg0){ - return tag.equals( arg0 ); + /** + * Wrangles the tag out of the collection. + * TODO: move all tags to maps rather then sets. Probably better. + */ + static void removeTagFromCollection(String tagValue, Collection tags) { + for ( Iterator iter = tags.iterator(); iter.hasNext(); ) { + Tag tag = (Tag) iter.next(); + if (tag.getTag().equals(tagValue)) { + iter.remove(); + return; + } + } } - - public int hashCode(){ - return tag.hashCode(); + + /** + * Copy the tags as new instances. + */ + static Set copyTags(Set originalSet) { + Set newTags = new HashSet(); + for ( Iterator iter = originalSet.iterator(); iter.hasNext(); ) { + Tag tag = (Tag) iter.next(); + newTags.add( new Tag( tag.getTag() ) ); + } + return newTags; } - } Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/HibernateUtil.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/HibernateUtil.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/HibernateUtil.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -14,12 +14,16 @@ import org.hibernate.cfg.Configuration; /** - * The usual hibernate helper, with a few tweaks. + * The usual infamous hibernate helper, with a few tweaks. + * I have made the sessionFactory non final to allow reconfiguration if necessary. + * * @author <a href="mailto:mic...@gm..."> Michael Neale</a> * */ public class HibernateUtil { + public static final String DROOLS_REPOSITORY_CONFIG = "drools-repository-db.cfg.xml"; + private static SessionFactory sessionFactory; static { @@ -44,7 +48,7 @@ registerPersistentClasses( cfg ); // cfg.setProperty("connection.username", "sa"); // cfg.setProperty("connection.password", ""); - cfg.configure("drools-repository-db.cfg.xml"); + cfg.configure(DROOLS_REPOSITORY_CONFIG); sessionFactory = cfg.buildSessionFactory(); } Added: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/ISaveHistory.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/ISaveHistory.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/ISaveHistory.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -0,0 +1,29 @@ +package org.drools.repository.db; + +/** + * Assets that implement this will have their history saved. + * Is partly a marker interface for persistence. + */ +public interface ISaveHistory extends IVersionable { + + /** + * This indicates the ID the the original asset was saved with. Allows + * a history list to be queried. + */ + Long getHistoricalId(); + void setHistoricalId(Long id); + + /** + * @return True is the object is actually a save history record. + */ + boolean isHistoricalRecord(); + void setHistoricalRecord(boolean b); + + /** + * + * @param oldObject Previous version of the object of this type. + * @return + */ + boolean isStateChanged(ISaveHistory oldObject); + +} Property changes on: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/ISaveHistory.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/IVersionable.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/IVersionable.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/IVersionable.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -0,0 +1,39 @@ +package org.drools.repository.db; + +/** + * All assets that support versioning must implement this. + * Versioning in this sense is "major" versioning, at the ruleset level. + * + * This is different to Save History versioning, which is implicit on save. + * + */ +public interface IVersionable { + + /** + * This is used to indicate that the asset is un-attached to + * any ruleset. Basically deleted. + * TODO: enhance this to delete if no longer needed. + */ + public static final long NO_VERSION = -1; + + /** of course they have to have an id ! + * Ids are always assigned by the database. + */ + Long getId(); + + /** Must create a fresh copy OF THE SAME TYPE, with a null Id */ + IVersionable copy(); + + /** + * The version number is used to group assets together in a RuleSet for instance + * The version number should ONLY be set by the repository, NOT by users. + */ + void setVersionNumber(long versionNumber); + + /** The version comment is used when major versions are created */ + void setVersionComment(String comment); + + String getVersionComment(); + + long getVersionNumber(); +} Property changes on: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/IVersionable.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/Persistent.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/Persistent.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/Persistent.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -0,0 +1,19 @@ +package org.drools.repository.db; + +import java.io.Serializable; + +/** The layer supertype for repository persistable classes. */ +public class Persistent implements Serializable { + + private Long id; + + public Long getId(){ + return id; + } + + private void setId(Long id){ + this.id = id; + } + + +} Property changes on: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/Persistent.java ___________________________________________________________________ Name: svn:eol-style + native Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/RepoProxyHandler.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/RepoProxyHandler.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/RepoProxyHandler.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -4,17 +4,25 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import org.drools.repository.RepositoryException; +import org.drools.repository.RepositoryManagerImpl; import org.hibernate.Session; +import org.hibernate.StaleObjectStateException; import org.hibernate.Transaction; /** * Dynamic proxy handler for all persistence operations. * Keeps the hibernate session and transaction handling away from the repository implementation. * + * It will enable the history filter before invoking any methods. + * * This is the glue between the actual implementation and the interface. - * Kind of like poor mans aspects. But I couldn't justify AOP for this little thing. * - * This provides the stateful and stateless behaviour. + * It also provides the stateful and stateless behaviour. + * Stateful simple means that a session instance is created the first time, and + * kept around (long running sessions). + * + * * It can also be extended to provide user context to the implementation class * (for auditing, access control and locking for instance). * @@ -25,7 +33,7 @@ InvocationHandler { - private RepositoryImpl repoImpl = new RepositoryImpl(); + private RepositoryManagerImpl repoImpl = new RepositoryManagerImpl(); private Session session = null; private boolean stateful = false; @@ -53,6 +61,13 @@ /** * This will initialise the session to the correct state. * Allows both stateless and stateful repository options. + * + * If an exception occurs in the Repo Impl, it will rollback + * the transaction. + * If the exception is of type RepositoryException, the session will be left + * alone. + * If the exception is of any other type then the session will be closed. + * */ public Object invoke(Object proxy, Method method, @@ -62,17 +77,14 @@ Session session = getCurrentSession(); if (this.stateful && method.getName().equals("close")) { - session.close(); - StoreEventListener.setCurrentConnection(null); - return null; + return handleCloseSession( session ); } Transaction tx = null; try { tx = session.beginTransaction(); configureSession( session ); - Object result = method.invoke(repoImpl, args); - session.flush(); + Object result = method.invoke(repoImpl, args); tx.commit(); if (!stateful) { @@ -82,16 +94,37 @@ } catch (InvocationTargetException e) { rollback( tx ); + checkForRepositoryException( session, e ); throw e.getTargetException(); } - catch (Exception e) { - rollback( tx ); - throw e; + + } + + /** + * If its an instance of RepositoryException, we don't want to close the session. + * It may just be a validation message being thrown. + */ + private void checkForRepositoryException(Session session, + InvocationTargetException e) { + if (! (e.getTargetException() instanceof RepositoryException)) { + try { + repoImpl.injectSession(null); + session.close(); + } catch (Exception e2) { /*ignore*/ } } } + /** + * Should really only be called for stateful repository instances. + */ + private Object handleCloseSession(Session session) { + session.close(); + StoreEventListener.setCurrentConnection(null); + return null; + } + private void rollback(Transaction tx) { - if (tx !=null) { + if (tx != null) { tx.rollback(); } } Deleted: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/RepositoryImpl.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/RepositoryImpl.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/RepositoryImpl.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -1,184 +0,0 @@ -package org.drools.repository.db; - -import java.util.List; - - -import org.drools.repository.RepositoryManager; -import org.drools.repository.RuleDef; -import org.drools.repository.RuleSetAttachment; -import org.drools.repository.RuleSetDef; -import org.hibernate.Session; - -/** - * The repository manager takes care of storing and sychronising the repository - * data with the repository database. - * - * @author <a href ="mailto:suj...@co..."> Sujit Pal </a> - * @author <a href="mailto:mic...@gm..."> Michael Neale</a> - */ -public class RepositoryImpl - implements - RepositoryManager { - - private Session session; - - public void injectSession(Session session) { - this.session = session; - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#save(org.drools.repository.RuleDef) - */ - public void save(RuleDef newRule) { - session.saveOrUpdate( newRule ); - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#loadRule(java.lang.String, long) - */ - public RuleDef loadRule(String ruleName, - long versionNumber) { - RuleDef result = (RuleDef) session.createQuery( "from RuleDef where name = :name and versionNumber = :version" ) - .setString( "name", ruleName ) - .setLong( "version", versionNumber ) - .uniqueResult(); - - return result; - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#listRuleVersions(java.lang.String) - */ - public List listRuleVersions(String ruleName) { - List result = (List) session.createQuery( "from RuleDef where name = :name order by versionNumber" ) - .setString( "name", ruleName ).list(); - return result; - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#listRuleSaveHistory(org.drools.repository.RuleDef) - */ - public List listRuleSaveHistory(RuleDef rule) { - disableHistoryFilter( session ); - - List result = (List) session.createQuery( "from RuleDef where historicalId = :id" ).setLong( "id", - rule.getId().longValue() ).list(); - - enableHistoryFilter( session ); - return result; - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#findRulesByTag(java.lang.String) - */ - public List findRulesByTag(String tag) { - List result = session.createQuery( "select rule from RuleDef as rule " + - "join rule.tags as tags " + - "where tags.tag = :tag" ).setString( "tag", tag ).list(); - return result; - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#save(org.drools.repository.RuleSetDef) - */ - public void save(RuleSetDef ruleSet) { - session.saveOrUpdate( ruleSet ); - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#loadRuleSet(java.lang.String, long) - */ - public RuleSetDef loadRuleSet(String ruleSetName, - long workingVersionNumber) { - session.clear(); //to make sure latest is loaded up, not stale - enableWorkingVersionFilter( workingVersionNumber, - session ); - RuleSetDef def = loadRuleSetByName( ruleSetName, - session ); - def.setWorkingVersionNumber( workingVersionNumber ); - - disableWorkingVersionFilter( session ); - return def; - } - - private RuleSetDef loadRuleSetByName(String ruleSetName, - Session session) { - RuleSetDef def = (RuleSetDef) session.createQuery( "from RuleSetDef where name = :name" ).setString( "name", - ruleSetName ).uniqueResult(); - return def; - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#loadAttachment(java.lang.String) - */ - public RuleSetAttachment loadAttachment(String name) { - RuleSetAttachment at = (RuleSetAttachment) session.createQuery( "from RuleSetAttachment where name = :name" ) - .setString( "name",name ).uniqueResult(); - return at; - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#save(org.drools.repository.RuleSetAttachment) - */ - public void save(RuleSetAttachment attachment) { - session.saveOrUpdate( attachment ); - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#listRuleSets() - */ - public List listRuleSets() { - List list = session.createQuery( "select distinct name from RuleSetDef where name is not null" ).list(); - return list; - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#delete(org.drools.repository.RuleDef) - */ - public void delete(RuleDef rule) { - session.delete( rule ); - } - - /* (non-Javadoc) - * @see org.drools.repository.db.RepositoryManager#searchRulesByTag(java.lang.String, java.lang.String) - */ - public List searchRulesByTag(String ruleSetName, - String tag) { - RuleSetDef def = loadRuleSetByName( ruleSetName, - session ); - List list = session.createFilter( def.getRules(), - "where this.tags.tag = :tag" ).setString( "tag", - tag ).list(); - - return list; - } - - - ////////////////////////// - // Filters follow - ////////////////////////// - void enableHistoryFilter(Session session) { - session.enableFilter( "historyFilter" ).setParameter( "viewHistory", - Boolean.FALSE ); - } - - void disableHistoryFilter(Session session) { - session.disableFilter( "historyFilter" ); - } - - void enableWorkingVersionFilter(long workingVersionNumber, - Session session) { - session.enableFilter( "workingVersionFilter" ).setParameter( "filteredVersionNumber", - new Long( workingVersionNumber ) ); - } - - void disableWorkingVersionFilter(Session session) { - session.disableFilter( "workingVersionFilter" ); - } - - - public void close() { /*implemented by the proxy */} - - - -} Modified: trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/StoreEventListener.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/StoreEventListener.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/java/org/drools/repository/db/StoreEventListener.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -3,7 +3,6 @@ import java.io.Serializable; import java.sql.Connection; -import org.drools.repository.ISaveHistory; import org.hibernate.EmptyInterceptor; import org.hibernate.LockMode; import org.hibernate.Session; @@ -38,9 +37,13 @@ return false; } + /** + * This will load up the old copy, and save it as a history record + * (with a different identity). + * Filters stop the history records from popping up in unwanted places . + */ private void handleSaveHistory(Object entity) { ISaveHistory versionable = (ISaveHistory) entity; - Session session = getSessionFactory().openSession( (Connection) currentConnection.get() ); ISaveHistory prev = (ISaveHistory) session.load( entity.getClass(), @@ -52,15 +55,15 @@ copy.setHistoricalRecord( true ); session.save( copy ); session.flush(); - session.close(); - System.out.println( "SAVING HISTORY COPY" ); + session.close(); } } /** * Used to set the current session so the interceptor can access it. - * @param session + * The idea is to share the same connection that any current transactions + * are using. */ public static void setCurrentConnection(Connection conn) { currentConnection.set(conn); Modified: trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleDef.hbm.xml =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleDef.hbm.xml 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleDef.hbm.xml 2006-01-18 11:33:40 UTC (rev 2131) @@ -8,12 +8,13 @@ <class name="org.drools.repository.RuleDef" table="RULE_DEFINITIONS" - entity-name="org.drools.repository.RuleDef" select-before-update="true"> + select-before-update="true" optimistic-lock="version"> <id name="id" column="RULE_ID"> <generator class="native"/> </id> - <property name="name"/> + <version name="lockingVersion" /> + <property name="name" /> <property name="versionNumber" /> <property name="content" type="text" /> <property name="status" /> Modified: trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleSetAttachment.hbm.xml =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleSetAttachment.hbm.xml 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleSetAttachment.hbm.xml 2006-01-18 11:33:40 UTC (rev 2131) @@ -11,14 +11,18 @@ <generator class="native"/> </id> - <property name="name" /> + <property name="name" not-null="true" /> <property name="typeOfAttachment" /> <property name="content" /> <property name="originalFileName" /> <property name="versionNumber" /> <property name="versionComment" /> - + <set name="tags" table="RULESET_ATTACHMENT_TAGS" lazy="false" cascade="all" optimistic-lock="false"> + <key column="RULESET_ATTACHMENT_ID"/> + <one-to-many class="org.drools.repository.Tag"/> + </set> + </class> </hibernate-mapping> \ No newline at end of file Modified: trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleSetDef.hbm.xml =================================================================== --- trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleSetDef.hbm.xml 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/main/resources/org/drools/repository/RuleSetDef.hbm.xml 2006-01-18 11:33:40 UTC (rev 2131) @@ -61,7 +61,7 @@ <filter name="workingVersionFilter" condition=":filteredVersionNumber = versionNumber" /> </set> - <set name="functions" lazy="false" cascade="all" optimistic-lock="false"> + <set name="functions" lazy="false" table="RULESET_FUNCTIONS" cascade="all" optimistic-lock="false"> <key column="RULESET_ID"/> <one-to-many class="org.drools.repository.FunctionDef"/> <filter name="workingVersionFilter" condition=":filteredVersionNumber = versionNumber" /> Modified: trunk/labs/jbossrules/drools-repository/src/test/java/org/drools/repository/AttachmentPersistTest.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/test/java/org/drools/repository/AttachmentPersistTest.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/test/java/org/drools/repository/AttachmentPersistTest.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -7,9 +7,11 @@ public void testLoadSave() { RuleSetAttachment at = new RuleSetAttachment("test","test", "test".getBytes(), "blah.xml" ); RepositoryManager repo = getRepo(); + at.addTag("RULESETAT"); repo.save(at); - RuleSetAttachment at2 = repo.loadAttachment("test"); + RuleSetAttachment at2 = repo.loadAttachment("test", 1); assertEquals("test", at2.getTypeOfAttachment()); + assertEquals("RULESETAT", ((Tag)at2.getTags().iterator().next()).getTag()); } } Modified: trunk/labs/jbossrules/drools-repository/src/test/java/org/drools/repository/IntegrationTest.java =================================================================== --- trunk/labs/jbossrules/drools-repository/src/test/java/org/drools/repository/IntegrationTest.java 2006-01-18 11:05:45 UTC (rev 2130) +++ trunk/labs/jbossrules/drools-repository/src/test/java/org/drools/repository/IntegrationTest.java 2006-01-18 11:33:40 UTC (rev 2131) @@ -2,11 +2,17 @@ import java.util.Iterator; import java.util.List; +import java.util.Random; +import org.hibernate.StaleObjectStateException; + import junit.framework.TestCase; /** * This integration test aims to do a full suite of scenarios. + * + * It also may take a lot longer to run then the other "unit" tests. + * * Including concurrent editing of rules, simulating multiple rules in parallel. * * Note that I am using stateful repository instances as it makes it easier to test. @@ -17,8 +23,6 @@ */ public class IntegrationTest extends TestCase { - - /** * This will all execute as one JUnit test. * Any failure will cause the test to stop, but this is not a unit test, @@ -26,15 +30,162 @@ */ public void testBootstrap() { runVersioningTests(); -// runAttachmentTests(); -// runConcurrentTests(); + runAttachmentTests(); + + runConcurrentTests(); // runLocalPersistTests(); } /** - * These tests show how it all hangs together. + * The purpose of this test is to simulate 2 different users editing rules + * in different session. Detached and all. + */ + private void runConcurrentTests() { + //2 repos, representing different users. + RepositoryManager repoA = RepositoryFactory.getStatefulRepository(); + RepositoryManager repoB = RepositoryFactory.getStatefulRepository(); + + + //Lets try a simple rule + RuleDef ruleA = new RuleDef("Concurrent 1", "content1"); + repoA.save(ruleA); + repoA.close(); + repoA = RepositoryFactory.getStatefulRepository(); + + //Bob loads it up, decides he wants to edit it. + RuleDef ruleB = repoB.loadRule("Concurrent 1", 1); + assertEquals("content1", ruleB.getContent()); + ruleB.setContent("bobs version"); + + //Michael also is editing his version. + ruleA.setContent("michaels version"); + + //oh dear, we can't both be write can we? + //but Bob is just a bit quicker ... + repoB.save(ruleB); + try { + repoA.save(ruleA); + fail(); + } catch (StaleObjectStateException e) { + assertNotNull(e.getMessage()); + } + + repoA = RepositoryFactory.getStatefulRepository(); + + + //now try some rulesets. + RuleSetDef ruleSet = new RuleSetDef("Integration concurrent 1", null); + ruleSet.addRule(new RuleDef("Concurrent 2", "abc").addTag("yeah")); + repoA.save(ruleSet); + repoA.close(); + + //we will add a rule to each one + repoA = RepositoryFactory.getStatefulRepository(); + repoB = RepositoryFactory.getStatefulRepository(); + +... [truncated message content] |