001    /*
002     * JBoss DNA (http://www.jboss.org/dna)
003     * See the COPYRIGHT.txt file distributed with this work for information
004     * regarding copyright ownership.  Some portions may be licensed
005     * to Red Hat, Inc. under one or more contributor license agreements.
006     * See the AUTHORS.txt file in the distribution for a full listing of 
007     * individual contributors. 
008     *
009     * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010     * is licensed to you under the terms of the GNU Lesser General Public License as
011     * published by the Free Software Foundation; either version 2.1 of
012     * the License, or (at your option) any later version.
013     *
014     * JBoss DNA is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * Lesser General Public License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this software; if not, write to the Free
021     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023     */
024    package org.jboss.dna.connector.store.jpa.model.basic;
025    
026    import java.util.UUID;
027    import javax.persistence.EntityManager;
028    import org.hibernate.ejb.Ejb3Configuration;
029    import org.jboss.dna.connector.store.jpa.JpaConnectorI18n;
030    import org.jboss.dna.connector.store.jpa.Model;
031    import org.jboss.dna.connector.store.jpa.model.common.ChangeLogEntity;
032    import org.jboss.dna.connector.store.jpa.model.common.NamespaceEntity;
033    import org.jboss.dna.connector.store.jpa.model.common.WorkspaceEntity;
034    import org.jboss.dna.graph.ExecutionContext;
035    import org.jboss.dna.graph.observe.Observer;
036    import org.jboss.dna.graph.request.CopyBranchRequest;
037    import org.jboss.dna.graph.request.DeleteBranchRequest;
038    import org.jboss.dna.graph.request.MoveBranchRequest;
039    import org.jboss.dna.graph.request.ReadBranchRequest;
040    import org.jboss.dna.graph.request.processor.RequestProcessor;
041    
042    /**
043     * Database model that stores node properties as opaque records and children as transparent records. Large property values are
044     * stored separately.
045     * <p>
046     * The set of tables used in this model includes:
047     * <ul>
048     * <li>Namespaces - the set of namespace URIs used in paths, property names, and property values.</li>
049     * <li>Properties - the properties for each node, stored in a serialized (and optionally compressed) form.</li>
050     * <li>Large values - property values larger than a certain size will be broken out into this table, where they are tracked by
051     * their SHA-1 has and shared by all properties that have that same value. The values are stored in a binary (and optionally
052     * compressed) form.</li>
053     * <li>Children - the children for each node, where each child is represented by a separate record. This approach makes it
054     * possible to efficiently work with nodes containing large numbers of children, where adding and removing child nodes is largely
055     * independent of the number of children. Also, working with properties is also completely independent of the number of child
056     * nodes.</li>
057     * <li>ReferenceChanges - the references from one node to another</li>
058     * <li>Subgraph - a working area for efficiently computing the space of a subgraph; see below</li>
059     * <li>Change log - a record of the changes that have been made to the repository. This is used to distribute change events across
060     * multiple distributed processes, and to allow a recently-connected client to identify the set of changes that have been made
061     * since a particular time or date. Changes are serialized into a binary, compressed format.</i></li>
062     * <li>Options - the parameters for this store's configuration (common to all models)</li>
063     * </ul>
064     * </p>
065     * <h3>Subgraph queries</h3>
066     * <p>
067     * This database model contains two tables that are used in an efficient mechanism to find all of the nodes in the subgraph below
068     * a certain node. This process starts by creating a record for the subgraph query, and then proceeds by executing a join to find
069     * all the children of the top-level node, and inserting them into the database (in a working area associated with the subgraph
070     * query). Then, another join finds all the children of those children and inserts them into the same working area. This continues
071     * until the maximum depth has been reached, or until there are no more children (whichever comes first). All of the nodes in the
072     * subgraph are then represented by records in the working area, and can be used to quickly and efficient work with the subgraph
073     * nodes. When finished, the mechanism deletes the records in the working area associated with the subgraph query.
074     * </p>
075     * <p>
076     * This subgraph query mechanism is extremely efficient, performing one join/insert statement <i>per level of the subgraph</i>,
077     * and is completely independent of the number of nodes in the subgraph. For example, consider a subgraph of node A, where A has
078     * 10 children, and each child contains 10 children, and each grandchild contains 10 children. This subgraph has a total of 1111
079     * nodes (1 root + 10 children + 10*10 grandchildren + 10*10*10 great-grandchildren). Finding the nodes in this subgraph would
080     * normally require 1 query per node (in other words, 1111 queries). But with this subgraph query mechanism, all of the nodes in
081     * the subgraph can be found with 1 insert plus 4 additional join/inserts.
082     * </p>
083     * <p>
084     * This mechanism has the added benefit that the set of nodes in the subgraph are kept in a working area in the database, meaning
085     * they don't have to be pulled into memory.
086     * </p>
087     * <p>
088     * Subgraph queries are used to efficiently process a number of different requests, including {@link ReadBranchRequest},
089     * {@link DeleteBranchRequest}, {@link MoveBranchRequest}, and {@link CopyBranchRequest}. Processing each of these kinds of
090     * requests requires knowledge of the subgraph, and in fact all but the <code>ReadBranchRequest</code> need to know the complete
091     * subgraph.
092     * </p>
093     * 
094     * @author Randall Hauch
095     */
096    public class BasicModel extends Model {
097    
098        public BasicModel() {
099            super("Basic", JpaConnectorI18n.basicModelDescription);
100        }
101    
102        /**
103         * {@inheritDoc}
104         * 
105         * @see org.jboss.dna.connector.store.jpa.Model#createRequestProcessor(String, ExecutionContext, Observer, EntityManager,
106         *      UUID, String, String[], long, boolean, boolean, boolean)
107         */
108        @Override
109        public RequestProcessor createRequestProcessor( String sourceName,
110                                                        ExecutionContext context,
111                                                        Observer observer,
112                                                        EntityManager entityManager,
113                                                        UUID rootNodeUuid,
114                                                        String nameOfDefaultWorkspace,
115                                                        String[] predefinedWorkspaceNames,
116                                                        long largeValueMinimumSizeInBytes,
117                                                        boolean creatingWorkspacesAllowed,
118                                                        boolean compressData,
119                                                        boolean enforceReferentialIntegrity ) {
120            return new BasicRequestProcessor(sourceName, context, observer, entityManager, rootNodeUuid, nameOfDefaultWorkspace,
121                                             predefinedWorkspaceNames, largeValueMinimumSizeInBytes, creatingWorkspacesAllowed,
122                                             compressData, enforceReferentialIntegrity);
123        }
124    
125        /**
126         * Configure the entity class that will be used by JPA to store information in the database.
127         * 
128         * @param configurator the Hibernate {@link Ejb3Configuration} component; never null
129         */
130        @Override
131        public void configure( Ejb3Configuration configurator ) {
132            // Add the annotated classes ...
133            configurator.addAnnotatedClass(WorkspaceEntity.class);
134            configurator.addAnnotatedClass(NamespaceEntity.class);
135            configurator.addAnnotatedClass(NodeId.class);
136            configurator.addAnnotatedClass(PropertiesEntity.class);
137            configurator.addAnnotatedClass(LargeValueEntity.class);
138            configurator.addAnnotatedClass(LargeValueId.class);
139            configurator.addAnnotatedClass(ChildEntity.class);
140            configurator.addAnnotatedClass(ChildId.class);
141            configurator.addAnnotatedClass(ReferenceEntity.class);
142            configurator.addAnnotatedClass(ReferenceId.class);
143            configurator.addAnnotatedClass(SubgraphQueryEntity.class);
144            configurator.addAnnotatedClass(SubgraphNodeEntity.class);
145            configurator.addAnnotatedClass(ChangeLogEntity.class);
146    
147            // Set the cache information for each persistent class ...
148            // configurator.setProperty("hibernate.ejb.classcache." + KidpackNode.class.getName(), "read-write");
149            // configurator.setProperty("hibernate.ejb.collectioncache" + KidpackNode.class.getName() + ".distributors",
150            // "read-write, RegionName");
151        }
152    
153    }