Package org.drools.repository

Source Code of org.drools.repository.RulesRepository$DateQuery

/**
* Copyright 2010 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.repository;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.jcr.ImportUUIDBehavior;
import javax.jcr.InvalidItemStateException;
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.query.Query;
import javax.jcr.query.QueryResult;

import org.drools.repository.events.StorageEventManager;
import org.drools.repository.migration.MigrateDroolsPackage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* RulesRepository is the class that defines the bahavior for the JBoss Rules
* (drools) rule repository based upon the JCR specification (JSR-170).
* <p>
* An instance of this class is capable of storing rules used by the JBoss Rule
* engine. It also provides a versioning capability for rules. Rules can be
* imported from specified files. The RulesRepository is also capable of storing
* DSL content. Rules can be explicitly tied to a particular DSL node within the
* repository, and this reference can either follow the head version, or a
* specific version of the DSL node.
* <p>
* Rules can be tagged. Tags are stored in a separate area of the repository,
* and can be added on demand. Rules can have 0 or more tags. Tags are intended
* to help provide a means for searching for specific types of rules quickly,
* even when they aren't all part of the same rulepackage.
* <p>
* Rules can be associated with 0 or 1 states. States are created in a seperate
* area of the repository. States are intended to help track the progress of a
* rule as it traverses its life- cycle. (e.g. draft, approved, deprecated,
* etc.)
* <p>
* The RulesRepository provides versioning of rules, rule packages, and DSLs.
* This versioning works in a strictly linear fashion, with one version having
* at most 1 predecessor version (or none, if it is the first version), and at
* most 1 successor version (or none, if it is the most recently checked-in
* version). The JCR specification supports a more complicated versioning
* system, and if there is sufficient demand, we can modify our versioning
* scheme to be better aligned with JCR's versioning abilities.
*
* @author Ben Truitt - with contributions from Michael Neale and Fernando Meyer over time.
*/
public class RulesRepository {

    public static final String  DEFAULT_PACKAGE       = "defaultPackage";

    public static final String  DROOLS_URI            = "http://www.jboss.org/drools-repository/1.0";

    private static final Logger log                   = LoggerFactory.getLogger( RulesRepository.class );

    /**
     * The name of the rulepackage area of the repository
     */
    public final static String  RULE_PACKAGE_AREA     = "drools:package_area";
    public final static String  RULE_GLOBAL_AREA     = "globalArea";

    /**
     * The name of the rulepackage area of the repository
     */
    public final static String  PACKAGE_SNAPSHOT_AREA = "drools:packagesnapshot_area";

    /**
     * The name of the tag area of the repository
     */
    public final static String  TAG_AREA              = "drools:tag_area";

    /**
     * The name of the state area of the repository
     */
    public final static String  STATE_AREA            = "drools:state_area";

    /**
     * The name of the rules repository within the JCR repository
     */
    public final static String  RULES_REPOSITORY_NAME = "drools:repository";

    private Session             session;

    static boolean              initialized           = false;

    /**
     * This requires a JCR session be setup, and the repository be configured.
     */
    public RulesRepository(Session session) {
        this.session = session;
        checkForDataMigration( this );
    }

    private synchronized static void checkForDataMigration(RulesRepository self) {
        if ( initialized ) return;
        if ( self.session.getUserID().equals( "anonymous" ) ) return;
        try {
            MigrateDroolsPackage migration = new MigrateDroolsPackage();
            if ( migration.needsMigration( self ) ) {
                migration.migrate( self );
            }
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }
        initialized = true;
    }

    /**
     * Will add a node named 'nodeName' of type 'type' to 'parent' if such a
     * node does not already exist.
     *
     * @param parent
     *            the parent node to add the new node to
     * @param nodeName
     *            the name of the new node
     * @param type
     *            the type of the new node
     * @return a reference to the Node object that is created by the addition,
     *         or, if the node already existed, a reference to the pre-existant
     *         node.
     * @throws RulesRepositoryException
     */
    protected static Node addNodeIfNew(Node parent,
                                       String nodeName,
                                       String type) throws RulesRepositoryException {
        Node node;
        try {
            node = parent.getNode( nodeName );
        } catch ( PathNotFoundException e ) {
            // it doesn't exist yet, so create it
            try {
        log.debug("Adding new node of type: {} named: {} to parent node named {}", new Object[] {type, nodeName, parent.getName()});
                node = parent.addNode( nodeName,
                                       type );
            } catch ( Exception e1 ) {
                log.error( "Caught Exception",
                           e );
                throw new RulesRepositoryException( e1 );
            }
        } catch ( Exception e ) {
            log.error( "Caught Exception", e );
            throw new RulesRepositoryException( e );
        }
        return node;
    }

    /**
     * Explicitly logout of the underlying JCR repository.
     */
    public void logout() {
        this.session.logout();
    }

    public Node getAreaNode(String areaName) throws RulesRepositoryException {
        Node folderNode = null;
        int tries = 0;
        while ( folderNode == null && tries < 2 ) {
            try {
                tries++;
                folderNode = this.session.getRootNode().getNode( RULES_REPOSITORY_NAME + "/" + areaName );
            } catch ( PathNotFoundException e ) {
                if ( tries == 1 ) {
                    // hmm..repository must have gotten screwed up. set it
                    // up again
                    log.warn( "The repository appears to have become corrupted." );
                    throw new RulesRepositoryException( "Unable to get the main rule repo node. Repository is not setup correctly.",
                                                        e );
                } else {
                    log.error( "Unable to correct repository corruption" );
                }
            } catch ( Exception e ) {
                log.error( "Caught Exception",
                           e );
                throw new RulesRepositoryException( "Caught exception " + e.getClass().getName(),
                                                    e );
            }
        }
        if ( folderNode == null ) {
            String message = "Could not get a reference to a node for " + RULES_REPOSITORY_NAME + "/" + areaName;
            log.error( message );
            throw new RulesRepositoryException( message );
        }
        return folderNode;
    }

    //    MN: This is kept for future reference showing how to tie references
    //    to a specific version when
    //    sharing assets.
    //
    //    /**
    //     * Adds a Rule node in the repository using the content specified,
    //     associating it with
    //     * the specified DSL node
    //     *
    //     * @param ruleName the name of the rule
    //     * @param lhsContent the lhs of the rule
    //     * @param rhsContent the rhs of the rule
    //     * @param dslItem the dslItem encapsulting the dsl node to associate
    //     this rule node with
    //     * @paaram followDslHead whether or not to follow the head revision of
    //     the dsl node
    //     * @return a RuleItem object encapsulating the node that gets added
    //     * @throws RulesRepositoryException
    //     */
    //    public RuleItem addRule(String ruleName, String ruleContent, DslItem
    //                            dslItem, boolean followDslHead) throws RulesRepositoryException {
    //        Node folderNode = this.getAreaNode(RULE_AREA);
    //
    //        try {
    //            //create the node - see section 6.7.22.6 of the spec
    //            Node ruleNode = folderNode.addNode(ruleName,
    //                                               RuleItem.RULE_NODE_TYPE_NAME);
    //
    //            ruleNode.setProperty(RuleItem.TITLE_PROPERTY_NAME, ruleName);
    //            ruleNode.setProperty(RuleItem.RULE_CONTENT_PROPERTY_NAME,
    //                                 ruleContent);
    //            ruleNode.setProperty(RuleItem.DESCRIPTION_PROPERTY_NAME, "");
    //            ruleNode.setProperty(RuleItem.FORMAT_PROPERTY_NAME,
    //                                 RuleItem.RULE_FORMAT);
    //
    //
    //            if(followDslHead) {
    //                ruleNode.setProperty(RuleItem.DSL_PROPERTY_NAME, dslItem.getNode());
    //            }
    //            else {
    //                //tie the ruleNode to specifically the current version of the dslNode
    //                ruleNode.setProperty(RuleItem.DSL_PROPERTY_NAME,
    //                                     dslItem.getNode().getBaseVersion());
    //            }
    //
    //            Calendar lastModified = Calendar.getInstance();
    //            ruleNode.setProperty(RuleItem.LAST_MODIFIED_PROPERTY_NAME,
    //                                 lastModified);
    //
    //            session.save();
    //
    //            try {
    //                ruleNode.checkin();
    //            }
    //            catch(UnsupportedRepositoryOperationException e) {
    //                String message = "Error: Caught
    //                    UnsupportedRepositoryOperationException when attempting to checkin
    //                    rule: " + ruleNode.getName() + ". Are you sure your JCR repository
    //                    supports versioning? ";
    //                        log.error(message + e);
    //                throw new RulesRepositoryException(message, e);
    //            }
    //
    //            return new RuleItem(this, ruleNode);
    //        }
    //        catch(Exception e) {
    //            log.error("Caught Exception", e);
    //            throw new RulesRepositoryException(e);
    //        }
    //    }
    //
    //
    //    /**
    //     * Adds a Rule node in the repository using the content specified
    //     *
    //     * @param ruleName the name of the rule
    //     * @param lhsContent the lhs of the rule
    //     * @param rhsContent the rhs of the rule
    //     * @return a RuleItem object encapsulating the node that gets added
    //     * @throws RulesRepositoryException
    //     */
    //    public RuleItem addRule(String ruleName, String ruleContent) throws
    //    RulesRepositoryException {
    //        Node folderNode = this.getAreaNode(RULE_AREA);
    //
    //        try {
    //            //create the node - see section 6.7.22.6 of the spec
    //            Node ruleNode = folderNode.addNode(ruleName,
    //                                               RuleItem.RULE_NODE_TYPE_NAME);
    //
    //            ruleNode.setProperty(RuleItem.TITLE_PROPERTY_NAME, ruleName);
    //
    //
    //            ruleNode.setProperty(RuleItem.DESCRIPTION_PROPERTY_NAME, "");
    //            ruleNode.setProperty(RuleItem.FORMAT_PROPERTY_NAME,
    //                                 RuleItem.RULE_FORMAT);
    //            ruleNode.setProperty(RuleItem.RULE_CONTENT_PROPERTY_NAME,
    //                                 ruleContent);
    //
    //            ruleNode.setProperty( VersionableItem.CHECKIN_COMMENT, "Initial" );
    //
    //
    //            Calendar lastModified = Calendar.getInstance();
    //            ruleNode.setProperty(RuleItem.LAST_MODIFIED_PROPERTY_NAME,
    //                                 lastModified);
    //
    //            session.save();
    //
    //            try {
    //                ruleNode.checkin();
    //            }
    //            catch(UnsupportedRepositoryOperationException e) {
    //                String message = "Error: Caught
    //                    UnsupportedRepositoryOperationException when attempting to checkin
    //                    rule: " + ruleNode.getName() + ". Are you sure your JCR repository
    //                    supports versioning? ";
    //                        log.error(message + e);
    //                throw new RulesRepositoryException(message, e);
    //            }
    //
    //            return new RuleItem(this, ruleNode);
    //        }
    //        catch(Exception e) {
    //            log.error("Caught Exception", e);
    //            throw new RulesRepositoryException(e);
    //        }
    //    }

    /**
     * This will copy an assets content to the new location.
     * @return the UUID of the new asset.
     */
    public String copyAsset(String uuidSource,
                            String destinationPackage,
                            String destinationName) {
        try {
            AssetItem source = loadAssetByUUID( uuidSource );
            String sourcePath = source.getNode().getPath();

            String destPath = this.getAreaNode( RULE_PACKAGE_AREA ).getPath() + "/" + destinationPackage + "/" + PackageItem.ASSET_FOLDER_NAME + "/" + destinationName;
            this.session.getWorkspace().copy( sourcePath,
                                              destPath );
            AssetItem dest = loadPackage( destinationPackage ).loadAsset( destinationName );
            //            if (dest.getContent() != null ) {
            //                dest.updateContent( dest.getContent().replaceAll( source.getName(), dest.getName() ) );
            //            }

            dest.updateStringProperty( destinationPackage,
                                       AssetItem.PACKAGE_NAME_PROPERTY );
            dest.node.setProperty( AssetItem.VERSION_NUMBER_PROPERTY_NAME,
                                   0 );
            dest.updateTitle( dest.getName() );
            dest.checkin( "Copied from " + source.getPackageName() + "/" + source.getName() );
            return dest.getUUID();
        } catch ( RepositoryException e ) {
            log.error( "Unable to copy asset.",
                       e );
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * Loads a RulePackage for the specified package name. Will throw an
     * exception if the specified rule package does not exist.
     *
     * @param name
     *            the name of the package to load
     * @return a RulePackageItem object
     */
    public PackageItem loadPackage(String name) throws RulesRepositoryException {
        try {
            Node folderNode = this.getAreaNode( RULE_PACKAGE_AREA );
            Node rulePackageNode = folderNode.getNode( name );

            return new PackageItem( this,
                                    rulePackageNode );
        } catch ( RepositoryException e ) {
          //the Global package should always exist. In case it is not (eg, when
          //an old db was imported to repo), we create it.
          if (RULE_GLOBAL_AREA.equals(name)) {
        log.info("Creating Global area as it does not exist yet.");
        return createPackage(RULE_GLOBAL_AREA,
            "the global area that holds sharable assets");
      } else {
        log.error("Unable to load a rule package. ", e);
        throw new RulesRepositoryException(
            "Unable to load a rule package. ", e);
      }

        }
    }

    public StateItem loadState(String name) throws RulesRepositoryException {
        try {
            Node folderNode = this.getAreaNode( STATE_AREA );
            Node ruleStateNode = folderNode.getNode( name );

            return new StateItem( this,
                                  ruleStateNode );
        } catch ( RepositoryException e ) {
            log.error( "Unable to load a status. ",
                       e );

            throw new RulesRepositoryException( "Unable to load a status. ",
                                                e );

        }
    }

    /**
     * This returns true if the repository contains the specified package name.
     */
    public boolean containsPackage(String name) {
        Node folderNode = this.getAreaNode( RULE_PACKAGE_AREA );
        try {
            return folderNode.hasNode( name );
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * Check if package is archived.
     */
    public boolean isPackageArchived(String name) {
        Node folderNode = this.getAreaNode( RULE_PACKAGE_AREA );
        try {
            Node node = folderNode.getNode( name );

            return node.getProperty( AssetItem.CONTENT_PROPERTY_ARCHIVE_FLAG ).getBoolean();
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }
    }

    public boolean containsSnapshot(String packageName,
                                    String snapshotName) {
        try {
            Node areaNode = this.getAreaNode( PACKAGE_SNAPSHOT_AREA );
            if ( !areaNode.hasNode( packageName ) ) return false;
            Node n = areaNode.getNode( packageName );
            return n.hasNode( snapshotName );
        } catch ( RepositoryException e ) {
            log.error( e.getMessage(), e );
            throw new RulesRepositoryException( e );
        }
    }

    public PackageItem loadPackageSnapshot(String packageName,
                                           String snapshotName) {
        try {
            Node n = this.getAreaNode( PACKAGE_SNAPSHOT_AREA ).getNode( packageName ).getNode( snapshotName );
            return new PackageItem( this,
                                    n );
        } catch ( RepositoryException e ) {
            log.error( e.getMessage(), e );
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * This will copy the package to the snapshot area. Creating a copy for
     * deployment, etc.
     */
    public void createPackageSnapshot(String packageName,
                                      String snapshotName) {
        log.debug( "Creating snapshot for [" + packageName + "] called [" + snapshotName + "]" );
        try {
            Node snaps = this.getAreaNode( PACKAGE_SNAPSHOT_AREA );

            if ( !snaps.hasNode( packageName ) ) {
                snaps.addNode( packageName,
                               "nt:folder" );
                save();
            }

            Node pkgSnaps = snaps.getNode( packageName );

            String newName = pkgSnaps.getPath() + "/" + snapshotName;

            Node folderNode = this.getAreaNode( RULE_PACKAGE_AREA );
            Node rulePackageNode = folderNode.getNode( packageName );

            String source = rulePackageNode.getPath();

            long start = System.currentTimeMillis();
            this.session.getWorkspace().copy( source,
                                              newName );
            log.debug("Time taken for snap: " + (System.currentTimeMillis() - start));

        } catch ( RepositoryException e ) {
            log.error( "Unable to create snapshot",
                       e );
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * This will remove the specified snapshot.
     */
    public void removePackageSnapshot(String packageName,
                                      String snapshotName) {
        log.debug( "Removing snapshot for [" + packageName + "] called [" + snapshotName + "]" );
        try {
            Node snaps = this.getAreaNode( PACKAGE_SNAPSHOT_AREA );

            if ( !snaps.hasNode( packageName ) ) {
                throw new RulesRepositoryException( "The package " + packageName + " does not have any snapshots." );
            }

            Node pkgSnaps = snaps.getNode( packageName );

            if ( pkgSnaps.hasNode( snapshotName ) ) {
                pkgSnaps.getNode( snapshotName ).remove();
            }

            save();
        } catch ( RepositoryException e ) {
            log.error( "Unable to remove snapshot",
                       e );
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * Copies a snapshot to the new location/label.
     * If one exists at that location, it will be replaced.
     *
     * @param packageName
     *            The name of the package.
     * @param snapshotName
     *            The label of the source snapshot
     * @param newName
     *            The new label. The old one is left intact.
     */
    public void copyPackageSnapshot(String packageName,
                                    String snapshotName,
                                    String newName) {
        log.debug( "Creating snapshot for [" + packageName + "] called [" + snapshotName + "]" );
        try {
            Node snaps = this.getAreaNode( PACKAGE_SNAPSHOT_AREA );

            Node pkgSnaps = snaps.getNode( packageName );


            Node sourceNode = pkgSnaps.getNode( snapshotName );
            if (pkgSnaps.hasNode(newName)) {
              pkgSnaps.getNode(newName).remove();
              this.session.save();
            }

            String destinationPath = pkgSnaps.getPath() + "/" + newName;



            this.session.getWorkspace().copy( sourceNode.getPath(),
                                              destinationPath );
        } catch ( RepositoryException e ) {
            log.error( "Unable to create snapshot",
                       e );
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * This will return or create the default package for rules that have no
     * home yet.
     */
    public PackageItem loadDefaultPackage() throws RulesRepositoryException {
        Node folderNode = this.getAreaNode( RULE_PACKAGE_AREA );
        try {
            if ( folderNode.hasNode( DEFAULT_PACKAGE ) ) {
                return loadPackage( DEFAULT_PACKAGE );
            } else {
                return createPackage( DEFAULT_PACKAGE,
                                      "" );
            }
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }

    }
   
    /**
     * This will return the global area for rules that can be shared.
     */
    public PackageItem loadGlobalArea() throws RulesRepositoryException {
        return loadPackage(RULE_GLOBAL_AREA);
    }

    /**
     * Similar to above. Loads a RulePackage for the specified uuid.
     *
     * @param uuid
     *            the uuid of the package to load
     * @return a RulePackageItem object
     * @throws RulesRepositoryException
     */
    public PackageItem loadPackageByUUID(String uuid) throws RulesRepositoryException {
        try {
            Node rulePackageNode = this.session.getNodeByIdentifier( uuid );
            return new PackageItem( this,
                                    rulePackageNode );
        } catch ( Exception e ) {
            log.error( "Unable to load a rule package by UUID. ",
                       e );
            if ( e instanceof RuntimeException ) {
                throw (RuntimeException) e;
            } else {
                throw new RulesRepositoryException( "Unable to load a rule package. ",
                                                    e );
            }
        }
    }

    /**
     * This will restore the historical version, save, and check it in as a new
     * version with the given comment.
     *
     * @param versionToRestore
     * @param headVersion
     * @param comment
     */
    public void restoreHistoricalAsset(AssetItem versionToRestore,
                                       AssetItem headVersion,
                                       String comment) {
        headVersion.checkout();

        if ( versionToRestore.isBinary() ) {
            headVersion.updateBinaryContentAttachment( versionToRestore.getBinaryContentAttachment() );
        } else {
            headVersion.updateContent( versionToRestore.getContent() );
        }

        headVersion.checkin( comment );
    }

    /**
     * Loads a rule by its UUID (generally the fastest way to load something).
     */
    public AssetItem loadAssetByUUID(String uuid) {
        try {
            Node rulePackageNode = this.session.getNodeByIdentifier( uuid );
            return new AssetItem( this,
                                  rulePackageNode );
        } catch (ItemNotFoundException e) {
          log.warn(e.getMessage(), e);
          throw new RulesRepositoryException("That item does not exist.");
        } catch ( RepositoryException e ) {

            log.error( "Unable to load a rule asset by UUID.",
                       e );
            throw new RulesRepositoryException( e );
        }

    }

    /**
     * Adds a package to the repository.
     *
     * @param name
     *            what to name the node added
     * @param description
     *            what description to use for the node
     * @return a PackageItem, encapsulating the created node
     * @throws RulesRepositoryException
     */ 
    public PackageItem createPackage(String name,
                                     String description) throws RulesRepositoryException {
        Node folderNode = this.getAreaNode( RULE_PACKAGE_AREA );

        try {
            // create the node - see section 6.7.22.6 of the spec
            Node rulePackageNode = folderNode.addNode( name,
                                                       PackageItem.RULE_PACKAGE_TYPE_NAME );

            rulePackageNode.addNode( PackageItem.ASSET_FOLDER_NAME,
                                     "drools:versionableAssetFolder" );

            rulePackageNode.setProperty( PackageItem.TITLE_PROPERTY_NAME,
                                         name );

            rulePackageNode.setProperty( AssetItem.DESCRIPTION_PROPERTY_NAME,
                                         description );
            rulePackageNode.setProperty( AssetItem.FORMAT_PROPERTY_NAME,
                                         PackageItem.PACKAGE_FORMAT );
            rulePackageNode.setProperty( PackageItem.CREATOR_PROPERTY_NAME,
                                         this.session.getUserID() );

            Calendar lastModified = Calendar.getInstance();
            rulePackageNode.setProperty( PackageItem.LAST_MODIFIED_PROPERTY_NAME,
                                         lastModified );

            PackageItem item = new PackageItem( this,
                                                rulePackageNode );
            item.checkin( "Initial" );

            if (StorageEventManager.hasSaveEvent()) {
                StorageEventManager.getSaveEvent().onPackageCreate(item);
            }

            return item;
        } catch ( ItemExistsException e ) {
            throw new RulesRepositoryException( "A package name must be unique.",
                                                e );
        } catch ( RepositoryException e ) {
            log.error( "Error when creating a new rule package",
                       e );
            throw new RulesRepositoryException( e );
        }

    }

    /**
     * Adds a Sub package to the repository.
     *
     * @param name
     *            what to name the node added
     * @param description
     *            what description to use for the node
     * @param parentPackage
     *         parent node under which this new package will be created
     * @return a PackageItem, encapsulating the created node
     * @throws RulesRepositoryException
     */ 
  public PackageItem createSubPackage(String name, String description, String parentPackage)
      throws RulesRepositoryException {

    try {
      PackageItem pkg = loadPackage(parentPackage);
      PackageItem subPkg = pkg.createSubPackage(name);

      // create the node - see section 6.7.22.6 of the spec
//      Node rulePackageNode = subPkg.node; // folderNode.addNode( name,
                        // PackageItem.RULE_PACKAGE_TYPE_NAME
                        // );

//      rulePackageNode.addNode(PackageItem.ASSET_FOLDER_NAME, "drools:versionableAssetFolder");

//      rulePackageNode.setProperty(PackageItem.TITLE_PROPERTY_NAME, name);
//      rulePackageNode.setProperty(AssetItem.DESCRIPTION_PROPERTY_NAME, description);
//      rulePackageNode.setProperty(AssetItem.FORMAT_PROPERTY_NAME, PackageItem.PACKAGE_FORMAT);
//      rulePackageNode.setProperty(PackageItem.CREATOR_PROPERTY_NAME, this.session.getUserID());
//
//      Calendar lastModified = Calendar.getInstance();
//      rulePackageNode.setProperty(PackageItem.LAST_MODIFIED_PROPERTY_NAME, lastModified);

      subPkg.checkin("Initial");

      if (StorageEventManager.hasSaveEvent()) {
        StorageEventManager.getSaveEvent().onPackageCreate(subPkg);
      }

      return subPkg;
    } catch (ItemExistsException e) {
      throw new RulesRepositoryException("A package name must be unique.", e);
    } catch (RepositoryException e) {
      log.error("Error when creating a new rule package", e);
      throw new RulesRepositoryException(e);
    }
  }
   
    /**
     * Gets a StateItem for the specified state name. If a node for the
     * specified state does not yet exist, one is first created.
     *
     * @param name
     *            the name of the state to get
     * @return a StateItem object encapsulating the retrieved node
     * @throws RulesRepositoryException
     */
    public StateItem getState(String name) throws RulesRepositoryException {
        try {
            Node folderNode = this.getAreaNode( STATE_AREA );
            if ( !folderNode.hasNode( name ) ) {
                throw new RulesRepositoryException( "The state called [" + name + "] does not exist." );
            }
            Node stateNode = folderNode.getNode( name );// RulesRepository.addNodeIfNew(folderNode,
            // name,
            // StateItem.STATE_NODE_TYPE_NAME);
            return new StateItem( this,
                                  stateNode );
        } catch ( Exception e ) {
            log.error( e.getMessage(), e );
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * Create a status node of the given name.
     */
    public StateItem createState(String name) {
        try {
            Node folderNode = this.getAreaNode( STATE_AREA );
            Node stateNode = RulesRepository.addNodeIfNew( folderNode,
                                                           name,
                                                           StateItem.STATE_NODE_TYPE_NAME );
            log.debug( "Created the status [" + name + "]" );
            return new StateItem( this,
                                  stateNode );
        } catch ( Exception e ) {
            log.error( e.getMessage(), e );
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * This will return a category for the given category path.
     *
     * @param tagName
     *            the name of the tag to get. If the tag to get is within a
     *            heirarchy of tag nodes, specify the full path to the tag node
     *            of interest (e.g. if you want to get back 'child-tag', use
     *            "parent-tag/child-tag")
     * @return a TagItem object encapsulating the node for the tag in the
     *         repository
     * @throws RulesRepositoryException
     */
    public CategoryItem loadCategory(String tagName) throws RulesRepositoryException {
        if ( tagName == null || "".equals( tagName ) ) {
            throw new RuntimeException( "Empty category name not permitted." );
        }

        try {
            Node folderNode = this.getAreaNode( TAG_AREA );
            Node tagNode = folderNode;

            StringTokenizer tok = new StringTokenizer( tagName,
                                                       "/" );
            while ( tok.hasMoreTokens() ) {
                String currentTagName = tok.nextToken();
                tagNode = folderNode.getNode( currentTagName );
                // MN was this: RulesRepository.addNodeIfNew(folderNode,
                // currentTagName, CategoryItem.TAG_NODE_TYPE_NAME);
                folderNode = tagNode;
            }

            return new CategoryItem( this,
                                     tagNode );
        } catch ( RepositoryException e ) {
            if ( e instanceof PathNotFoundException ) {
                throw new RulesRepositoryException( "Unable to load the category : [" + tagName + "] does not exist.",
                                                    e );
            }
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * This will retrieve a list of RuleItem objects - that are allocated to the
     * provided category. Only the latest versions of each RuleItem will be
     * returned (you will have to delve into the rules deepest darkest history
     * yourself... mahahahaha).
     *
     */
    public AssetPageList findAssetsByCategory(String categoryTag,
                                              boolean seekArchivedAsset,
                                              int skip,
                                              int numRowsToReturn) throws RulesRepositoryException {
        return findAssetsByCategory( categoryTag,
                                     seekArchivedAsset,
                                     skip,
                                     numRowsToReturn,
                                     null );
    }

    /**
     * This will retrieve a list of RuleItem objects - that are allocated to the
     * provided category. Only the latest versions of each RuleItem will be
     * returned (you will have to delve into the rules deepest darkest history
     * yourself... mahahahaha).
     *
     * Pass in startRow of 0 to start at zero, numRowsToReturn can be set to -1 should you want it all.
     * @param filter an AssetItem filter
     */
    public AssetPageList findAssetsByCategory(String categoryTag,
                                              boolean seekArchivedAsset,
                                              int skip,
                                              int numRowsToReturn,
                                              RepositoryFilter filter) throws RulesRepositoryException {
        CategoryItem item = this.loadCategory( categoryTag );

        try {
            return loadLinkedAssets( seekArchivedAsset,
                                     skip,
                                     numRowsToReturn,
                                     item.getNode(),
                                     filter );
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * Finds the AssetItem's linked to the requested state.
     * Similar to finding by category.
     */
    public AssetPageList findAssetsByState(String stateName,
                                           boolean seekArchivedAsset,
                                           int skip,
                                           int numRowsToReturn) throws RulesRepositoryException {
        return findAssetsByState( stateName,
                                  seekArchivedAsset,
                                  skip,
                                  numRowsToReturn,
                                  null );
    }

    /**
     * Finds the AssetItem's linked to the requested state.
     * Similar to finding by category.
     * @param filter an AssetItem filter
     *
     */
    public AssetPageList findAssetsByState(String stateName,
                                           boolean seekArchivedAsset,
                                           int skip,
                                           int numRowsToReturn,
                                           RepositoryFilter filter) throws RulesRepositoryException {
        StateItem item = this.getState( stateName );
        try {
            return loadLinkedAssets( seekArchivedAsset,
                                     skip,
                                     numRowsToReturn,
                                     item.getNode(),
                                     filter );
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }
    }

    private AssetPageList loadLinkedAssets(boolean seekArchivedAsset,
                                           int skip,
                                           int numRowsToReturn,
                                           Node n,
                                           RepositoryFilter filter) throws RepositoryException {
        int rows = 0;
        List<AssetItem> results = new ArrayList<AssetItem>();

        PropertyIterator it = n.getReferences();
        if ( skip > 0 ) it.skip( skip );

        while ( it.hasNext() && (numRowsToReturn == -1 || rows < numRowsToReturn) ) {

            Property ruleLink = (Property) it.next();

            Node parentNode = ruleLink.getParent();
            if ( isNotSnapshot( parentNode ) && parentNode.getPrimaryNodeType().getName().equals( AssetItem.RULE_NODE_TYPE_NAME ) ) {
                if ( seekArchivedAsset || !parentNode.getProperty( AssetItem.CONTENT_PROPERTY_ARCHIVE_FLAG ).getBoolean() ) {
                    AssetItem ai = new AssetItem( this, parentNode );
                    if ( filter == null || filter.accept( ai, "package.readonly")) {
                        results.add( ai );
                        rows++;
                    }
                }
            }
        }

        return new AssetPageList(results, it);
    }

    public AssetPageList findAssetsByCategory(String categoryTag,
                                              int skip,
                                              int numRowsToReturn) throws RulesRepositoryException {
        return this.findAssetsByCategory( categoryTag,
                                          false,
                                          skip,
                                          numRowsToReturn );
    }

    public void exportRulesRepositoryToStream(OutputStream output) {
        try {
            session.refresh( false );
            session.exportSystemView( "/" + RULES_REPOSITORY_NAME,
                                      output,
                                      false,
                                      false );
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RulesRepositoryException(e);
        }

    }



    public byte[] exportPackageFromRepository(String packageName) throws IOException,
                                                                 PathNotFoundException,
                                                                 RepositoryException {

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ZipOutputStream zout = new ZipOutputStream( bout );

        zout.putNextEntry( new ZipEntry( "repository_export.xml" ) );
        zout.write( dumpPackageFromRepositoryXml( packageName ) );
        zout.closeEntry();
        zout.finish();
        return bout.toByteArray();
    }



    public byte[] dumpPackageFromRepositoryXml(String packageName) throws PathNotFoundException,
                                                                  IOException,
                                                                  RepositoryException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        session.refresh( false );
        session.exportSystemView( "/" + RULES_REPOSITORY_NAME + "/" + RULE_PACKAGE_AREA + "/" + packageName,
                                  byteOut,
                                  false,
                                  false );
        return byteOut.toByteArray();
    }

    /**
     * Import the repository from a stream.
     */
    public void importRepository(InputStream in) {
        new RulesRepositoryAdministrator( this.session ).clearRulesRepository();
        try {
          this.session.getWorkspace().importXML( "/", in,
                                                 ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW );
          session.save();
        } catch (RepositoryException e) {
          throw new RulesRepositoryException(e);
        } catch (IOException e) {
          throw new RulesRepositoryException(e);
    }
    }

   
    /**
     * Clean and import the rules repository.
     * Will run any needed migrations as well.
     */
    public void importRulesRepositoryFromStream(InputStream instream) {
        try {
            new RulesRepositoryAdministrator( this.session ).clearRulesRepository();
            this.session.getWorkspace().importXML( "/",
                                                   instream,
                                                   ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW );
            session.save();
            MigrateDroolsPackage mig = new MigrateDroolsPackage();
            if ( mig.needsMigration( this ) ) {
                mig.migrate( this );
            }
        } catch ( ItemExistsException e ) {
            String message = "Item already exists. At least two items with the path: " + e.getLocalizedMessage();
            log.error( message,
                       e );
            throw new RulesRepositoryException( message );
        } catch ( RepositoryException e ) {
            log.error(e.getMessage(), e);
            throw new RulesRepositoryException("Repository error when importing from stream.", e);
        } catch ( IOException e ) {
            log.error(e.getMessage(), e);
            throw new RulesRepositoryException(e);

        }
    }



    public void importPackageToRepository(byte[] byteArray,
                                          boolean importAsNew) {
        try {
            if ( importAsNew ) {
                this.session.getWorkspace().importXML( "/" + RULES_REPOSITORY_NAME + "/" + RULE_PACKAGE_AREA + "/",
                                                       new ByteArrayInputStream( byteArray ),
                                                       ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW );

            } else {

                this.session.getWorkspace().importXML( "/" + RULES_REPOSITORY_NAME + "/" + RULE_PACKAGE_AREA + "/",
                                                       new ByteArrayInputStream( byteArray ),
                                                       ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING );
            }
            session.save();
            MigrateDroolsPackage mig = new MigrateDroolsPackage();
            if ( mig.needsMigration( this ) ) {
                mig.migrate( this );
            }
        } catch ( RepositoryException e ) {
            log.error(e.getMessage(), e);
            throw new RulesRepositoryException(e);
        } catch ( IOException e ) {
            log.error(e.getMessage(), e);
            throw new RulesRepositoryException(e);
        }
    }

    /**
     *
     * @param parentNode
     * @return
     * @throws RepositoryException
     */
    boolean isNotSnapshot(Node parentNode) throws RepositoryException {
        return parentNode.getPath().indexOf( PACKAGE_SNAPSHOT_AREA ) == -1;
    }

    /**
     * @return an Iterator which will provide RulePackageItem's. This will show
     *         ALL the packages, only returning latest versions, by default.
     */
    public PackageIterator listPackages() {
        Node folderNode = this.getAreaNode( RULE_PACKAGE_AREA );

        try {
            synchronized ( RulesRepository.class ) {
                if ( !folderNode.hasNode( DEFAULT_PACKAGE ) ) {
                    createPackage( DEFAULT_PACKAGE,
                                   "The default rule package" );
                    folderNode = this.getAreaNode( RULE_PACKAGE_AREA );
                }
            }
            return new PackageIterator( this,
                                        folderNode.getNodes() );
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * @return The JCR session that this repository is using.
     */
    public Session getSession() {
        return this.session;
    }

    /**
     * Save any pending changes.
     */
    public void save() {
        try {
            this.session.save();
        } catch ( InvalidItemStateException e ) {
          String message = "Your operation was failed because it conflicts with a change made through another user. Please try again.";
            log.error( "Caught Exception", e );
            throw new RulesRepositoryException( message, e );
        } catch ( Exception e ) {
            if ( e instanceof RuntimeException ) {
                throw (RuntimeException) e;
            } else {
                throw new RulesRepositoryException( e );
            }
        }

    }

    /**
     * This moves a rule asset from one package to another, preserving history
     * etc etc.
     *
     * @param newPackage
     *            The destination package.
     * @param uuid
     *            The UUID of the rule
     * @param explanation
     *            The reason (which will be added as the checkin message).
     */
    public void moveRuleItemPackage(String newPackage,
                                    String uuid,
                                    String explanation) {
        try {
            AssetItem item = loadAssetByUUID( uuid );

            PackageItem destPkg = loadPackage( newPackage );

            String sourcePath = item.node.getPath();
            String destPath = destPkg.node.getPath() + "/" + PackageItem.ASSET_FOLDER_NAME + "/" + item.getName();

            this.session.move( sourcePath,
                               destPath );
            this.session.save();
           
            item.checkout();
            item.node.setProperty( AssetItem.PACKAGE_NAME_PROPERTY,
                                   newPackage );

            item.checkin( explanation );

        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }

    }

    /**
     * This will rename an assset and apply the change immediately.
     * @return the UUID of the new asset
     */
    public String renameAsset(String uuid,
                              String newAssetName) {
        try {
            AssetItem itemOriginal = loadAssetByUUID( uuid );
            log.info( "Renaming asset: " + itemOriginal.getNode().getPath() + " to " + newAssetName );
            Node node = itemOriginal.getNode();
            String sourcePath = node.getPath();
            String destPath = node.getParent().getPath() + "/" + newAssetName;
            this.session.move( sourcePath,
                               destPath );
            this.session.save();

            itemOriginal.updateTitle( newAssetName );
            itemOriginal.checkin( "Renamed asset " + itemOriginal.getName() );
            return itemOriginal.getUUID();
        } catch ( RepositoryException e ) {
            log.error( e.getMessage(), e );
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * Rename a category.
     * @param originalPath The full path to the category.
     * @param newName The new name (just the name, not the path).
     */
    public void renameCategory(String originalPath,
                               String newName) {
        try {
            CategoryItem cat = loadCategory( originalPath );
            Node node = cat.getNode();
            String sourcePath = node.getPath();
            String destPath = node.getParent().getPath() + "/" + newName;
            this.session.move( sourcePath,
                               destPath );
            save();
        } catch ( RepositoryException e ) {
            log.error( e.getMessage(), e );
            throw new RulesRepositoryException( e );
        }
    }

    public void renameState(String oldName,
                            String newName) {
        try {
            StateItem state = loadState( oldName );
            Node node = state.getNode();
            String sourcePath = node.getPath();
            String destPath = node.getParent().getPath() + "/" + newName;
            this.session.move( sourcePath,
                               destPath );
            save();
        } catch ( RepositoryException e ) {
            log.error( e.getMessage(), e );
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * This will rename a package and apply the change immediately.
     * @return the UUID of the package
     */
    public String renamePackage(String uuid,
                                String newPackageName) {
        try {
            PackageItem itemOriginal = loadPackageByUUID( uuid );
            log.info( "Renaming package: " + itemOriginal.getNode().getPath() + " to " + newPackageName );
            Node node = itemOriginal.getNode();
            String sourcePath = node.getPath();
            String destPath = node.getParent().getPath() + "/" + newPackageName;
            this.session.move( sourcePath,
                               destPath );
           
            this.session.save();

            itemOriginal.updateTitle( newPackageName );
            itemOriginal.checkin( "Renamed package " + itemOriginal.getName() );

            PackageItem newPkg = loadPackage( newPackageName );

            for ( Iterator iter = newPkg.getAssets(); iter.hasNext(); ) {
                AssetItem as = (AssetItem) iter.next();
                as.updateStringProperty( newPackageName,
                                         AssetItem.PACKAGE_NAME_PROPERTY );
            }

            save();

            return itemOriginal.getUUID();
        } catch ( RepositoryException e ) {
            log.error( e.getMessage(), e );
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * Return a list of the snapshots available for the given package name.
     */
    public String[] listPackageSnapshots(String packageName) {
        Node snaps = this.getAreaNode( PACKAGE_SNAPSHOT_AREA );
        try {
            if ( !snaps.hasNode( packageName ) ) {
                return new String[0];
            } else {
                List result = new ArrayList();
                NodeIterator it = snaps.getNode( packageName ).getNodes();
                while ( it.hasNext() ) {
                    Node element = (Node) it.next();
                    result.add( element.getName() );
                }
                return (String[]) result.toArray( new String[result.size()] );
            }
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }
    }

    public AssetItemIterator findArchivedAssets() {
        try {

            String sql = "SELECT " + AssetItem.TITLE_PROPERTY_NAME + ", " + AssetItem.DESCRIPTION_PROPERTY_NAME + ", " + AssetItem.CONTENT_PROPERTY_ARCHIVE_FLAG + " FROM " + AssetItem.RULE_NODE_TYPE_NAME;
            sql += " WHERE ";
            sql += " jcr:path LIKE '/" + RULES_REPOSITORY_NAME + "/" + RULE_PACKAGE_AREA + "/%'";
            sql += " AND " + AssetItem.CONTENT_PROPERTY_ARCHIVE_FLAG + " = 'true'";

            Query q = this.session.getWorkspace().getQueryManager().createQuery( sql,
                                                                                 Query.SQL );

            QueryResult res = q.execute();

            return new AssetItemIterator( res.getNodes(),
                                          this );
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * This will search assets, looking for matches against the name.
     */
    public AssetItemIterator findAssetsByName(String name,
                                              boolean seekArchived) {
        try {

            String sql = "SELECT " + AssetItem.TITLE_PROPERTY_NAME + ", " + AssetItem.DESCRIPTION_PROPERTY_NAME + ", " + AssetItem.CONTENT_PROPERTY_ARCHIVE_FLAG + " FROM " + AssetItem.RULE_NODE_TYPE_NAME;
            sql += " WHERE " + AssetItem.TITLE_PROPERTY_NAME + " LIKE '" + name + "'";
            sql += " AND jcr:path LIKE '/" + RULES_REPOSITORY_NAME + "/" + RULE_PACKAGE_AREA + "/%'";

            if ( seekArchived == false ) {
                sql += " AND " + AssetItem.CONTENT_PROPERTY_ARCHIVE_FLAG + " = 'false'";
            }

            Query q = this.session.getWorkspace().getQueryManager().createQuery( sql,
                                                                                 Query.SQL );

            QueryResult res = q.execute();

            return new AssetItemIterator( res.getNodes(),
                                          this );
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * This will search assets, looking for matches against the name.
     */
    public AssetItemIterator queryFullText(String qry,
                                           boolean seekArchived) {
        try {

            String searchPath = "/jcr:root/" + RULES_REPOSITORY_NAME + "/" + RULE_PACKAGE_AREA + "//element(*, " + AssetItem.RULE_NODE_TYPE_NAME + ")";
            if ( seekArchived ) {
                searchPath += "[jcr:contains(., '" + qry + "')]";
            } else {
                searchPath += "[jcr:contains(., '" + qry + "') and " + AssetItem.CONTENT_PROPERTY_ARCHIVE_FLAG + " = 'false']";
            }
            Query q = this.session.getWorkspace().getQueryManager().createQuery( searchPath,
                                                                                 Query.XPATH );
            QueryResult res = q.execute();
            return new AssetItemIterator( res.getNodes(),
                                          this );
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * This will do a general predicate search.
     * @param params - a map of field to a list of possible values (which are or-ed together if there is more then one).
     * @param position - where to start returning results from.
     * @param maxRows - maximum number of rows to return;
     * @param seekArchived - include archived stuff in the results.
     */
    public AssetItemIterator query(Map<String, String[]> params,
                                   boolean seekArchived,
                                   DateQuery[] dates) {
        try {

            String sql = "SELECT " + AssetItem.TITLE_PROPERTY_NAME + ", " + AssetItem.DESCRIPTION_PROPERTY_NAME + ", " + AssetItem.CONTENT_PROPERTY_ARCHIVE_FLAG + " FROM " + AssetItem.RULE_NODE_TYPE_NAME;
            sql += " WHERE jcr:path LIKE '/" + RULES_REPOSITORY_NAME + "/" + RULE_PACKAGE_AREA + "/%'";
            for ( Iterator<Map.Entry<String, String[]>> iterator = params.entrySet().iterator(); iterator.hasNext(); ) {
                Map.Entry<String, String[]> en = iterator.next();
                String fld = en.getKey();
                String[] options = en.getValue();
                if ( options != null && options.length > 0 ) {
                    if ( options.length > 1 ) {
                        sql += " AND (";
                        for ( int i = 0; i < options.length; i++ ) {
                            sql += fld + " LIKE '" + options[i].replace( "*",
                                                                         "%" ) + "'";
                            if ( i < options.length - 1 ) {
                                sql += " OR ";
                            }
                        }
                        sql += ")";
                    } else {
                        sql += " AND " + fld + " LIKE '" + options[0].replace( "*",
                                                                               "%" ) + "'";
                    }
                }
            }
            if ( seekArchived == false ) {
                sql += " AND " + AssetItem.CONTENT_PROPERTY_ARCHIVE_FLAG + " = 'false'";
            }

            if ( dates != null ) {
                for ( int i = 0; i < dates.length; i++ ) {
                    DateQuery d = dates[i];
                    if ( d.after != null ) {
                        sql += " AND " + d.field + " > TIMESTAMP '" + d.after + "'";
                    }
                    if ( d.before != null ) {
                        sql += " AND " + d.field + " < TIMESTAMP '" + d.before + "'";
                    }
                }
            }


            Query q = this.session.getWorkspace().getQueryManager().createQuery( sql,
                                                                                 Query.SQL );

            QueryResult res = q.execute();

            return new AssetItemIterator( res.getNodes(),
                                          this );
        } catch ( RepositoryException e ) {
            throw new RulesRepositoryException( e );
        }
    }

    /**
     * Used for querying based on date.
     * @author Michael Neale
     */
    public static class DateQuery {
        private String after;
        private String before;
        private String field;

        public DateQuery(String field,
                         String after,
                         String before) {
            this.field = field;
            this.after = after;
            this.before = before;
        }
    }

    public AssetItemIterator findAssetsByName(String name) {
        return this.findAssetsByName( name,
                                      false );
    }

    /**
     * @return A list of statii in the system.
     */
    public StateItem[] listStates() {
        List states = new ArrayList();
        NodeIterator it;
        try {
            it = this.getAreaNode( STATE_AREA ).getNodes();

            while ( it.hasNext() ) {
                states.add( new StateItem( this,
                                           it.nextNode() ) );
            }
        } catch ( RepositoryException e ) {
            log.error( e.getMessage(), e );
            throw new RulesRepositoryException( e );
        }
        return (StateItem[]) states.toArray( new StateItem[states.size()] );
    }

    /**
     * Copy a package to the target name.
     */
    public void copyPackage(String sourcePackageName,
                            String destPackageName) {
        PackageItem source = loadPackage( sourcePackageName );
        String sourcePath;

        try {
            sourcePath = source.getNode().getPath();

            String destPath = source.getNode().getParent().getPath() + "/" + destPackageName;
            if ( this.getAreaNode( RULE_PACKAGE_AREA ).hasNode( destPackageName ) ) {
                throw new RulesRepositoryException( "Destination already exists." );
            }
            this.session.getWorkspace().copy( sourcePath,
                                              destPath );

            PackageItem newPkg = loadPackage( destPackageName );

            for ( Iterator iter = newPkg.getAssets(); iter.hasNext(); ) {
                AssetItem as = (AssetItem) iter.next();
                as.updateStringProperty( destPackageName,
                                         AssetItem.PACKAGE_NAME_PROPERTY );
            }

            save();

        } catch ( RepositoryException e ) {
            log.error( e.getMessage(), e );
            throw new RulesRepositoryException( e );
        }

    }

    @Override
    protected void finalize() throws Throwable {
        //shouldn't rely on this... but
        try {
            this.logout();
        } catch ( Exception e ) {
            log.error( "Finalizer error: " + e.getMessage() );
        }
    }
}
TOP

Related Classes of org.drools.repository.RulesRepository$DateQuery

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.