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 }