View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.jcr;
25  
26  import java.util.Arrays;
27  import java.util.List;
28  import javax.jcr.PropertyType;
29  import javax.jcr.RepositoryException;
30  import javax.jcr.Value;
31  import javax.jcr.nodetype.NodeDefinition;
32  import javax.jcr.nodetype.NodeTypeTemplate;
33  import javax.jcr.nodetype.PropertyDefinition;
34  import javax.jcr.version.OnParentVersionAction;
35  import net.jcip.annotations.NotThreadSafe;
36  import org.modeshape.graph.ExecutionContext;
37  import org.modeshape.graph.Graph;
38  import org.modeshape.graph.JcrLexicon;
39  import org.modeshape.graph.JcrNtLexicon;
40  import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource;
41  import org.modeshape.graph.io.Destination;
42  import org.modeshape.graph.io.GraphBatchDestination;
43  import org.modeshape.graph.property.Name;
44  import org.modeshape.graph.property.NameFactory;
45  import org.modeshape.graph.property.Path;
46  import org.modeshape.graph.property.PathFactory;
47  import org.modeshape.graph.property.PropertyFactory;
48  import org.modeshape.graph.property.ValueFactory;
49  import org.modeshape.jcr.nodetype.InvalidNodeTypeDefinitionException;
50  
51  /**
52   * Class to convert one or more {@link NodeTypeTemplate node type templates} containing custom node type definitions into a format
53   * that can be registered with the {@link JcrNodeTypeManager}.
54   * <p>
55   * As the JSR-283 specification mandates that node type templates be the standard basis for custom type registration, the
56   * {@link RepositoryNodeTypeManager#registerNodeTypes(java.util.Collection, boolean)} method should be used in preference to
57   * manually instantiating this class.
58   * </p>
59   */
60  @NotThreadSafe
61  class NodeTemplateNodeTypeSource implements JcrNodeTypeSource {
62  
63      private final Graph graph;
64      private final PathFactory pathFactory;
65      private final NameFactory nameFactory;
66      private final ValueFactory<Boolean> booleanFactory;
67      private final ValueFactory<String> stringFactory;
68      private final Destination destination;
69  
70      public NodeTemplateNodeTypeSource( NodeTypeTemplate nodeTypeTemplate ) throws InvalidNodeTypeDefinitionException {
71          this(Arrays.asList(new NodeTypeTemplate[] {nodeTypeTemplate}));
72      }
73  
74      public NodeTemplateNodeTypeSource( List<NodeTypeTemplate> nodeTypeTemplates ) throws InvalidNodeTypeDefinitionException {
75  
76          ExecutionContext context = null;
77  
78          if (nodeTypeTemplates.isEmpty()) {
79              context = new ExecutionContext();
80          } else {
81              for (NodeTypeTemplate ntt : nodeTypeTemplates) {
82                  if (!(ntt instanceof JcrNodeTypeTemplate)) {
83                      throw new IllegalArgumentException(JcrI18n.cannotConvertValue.text(ntt.getClass(), JcrNodeTypeTemplate.class));
84                  }
85  
86                  JcrNodeTypeTemplate jntt = (JcrNodeTypeTemplate)ntt;
87                  if (context == null) {
88                      context = jntt.getExecutionContext();
89                      assert context != null;
90                  } else {
91                      if (context != jntt.getExecutionContext()) {
92                          throw new IllegalArgumentException(JcrI18n.allNodeTypeTemplatesMustComeFromSameSession.text());
93                      }
94                  }
95              }
96          }
97  
98          assert context != null;
99          this.pathFactory = context.getValueFactories().getPathFactory();
100         this.nameFactory = context.getValueFactories().getNameFactory();
101         this.booleanFactory = context.getValueFactories().getBooleanFactory();
102         this.stringFactory = context.getValueFactories().getStringFactory();
103 
104         PathFactory pathFactory = context.getValueFactories().getPathFactory();
105         InMemoryRepositorySource source = new InMemoryRepositorySource();
106         source.setName("NodeTypeTemplate Import Source");
107         this.graph = Graph.create(source, context);
108         Graph.Batch batch = graph.batch();
109         destination = new GraphBatchDestination(batch);
110 
111         Path rootPath = pathFactory.createRootPath();
112         for (NodeTypeTemplate template : nodeTypeTemplates) {
113             this.createNodeType((JcrNodeTypeTemplate)template, rootPath);
114         }
115 
116         destination.submit();
117     }
118 
119     /**
120      * {@inheritDoc}
121      * 
122      * @see org.modeshape.jcr.JcrNodeTypeSource#getNodeTypes()
123      */
124     public final Graph getNodeTypes() {
125         return graph;
126     }
127 
128     private boolean booleanFrom( Object value,
129                                  boolean defaultValue ) {
130         if (value == null) return defaultValue;
131 
132         return booleanFactory.create(value);
133     }
134 
135     private Name nameFrom( Object value ) {
136         return nameFactory.create(value);
137     }
138 
139     private Name[] namesFrom( Object[] values ) {
140         if (values == null) return new Name[0];
141 
142         Name[] names = new Name[values.length];
143         for (int i = 0; i < values.length; i++) {
144             names[i] = nameFactory.create(values[i]);
145         }
146 
147         return names;
148     }
149 
150     private String[] stringsFrom( Object[] values ) {
151         if (values == null) return new String[0];
152 
153         String[] strings = new String[values.length];
154         for (int i = 0; i < values.length; i++) {
155             strings[i] = stringFactory.create(values[i]);
156         }
157 
158         return strings;
159     }
160 
161     /**
162      * Project the custom node type definition from the given template onto the {@link #getNodeTypes() graph}.
163      * 
164      * @param nodeType
165      * @param parentPath
166      * @return the path to the newly created node
167      * @throws InvalidNodeTypeDefinitionException
168      */
169     protected Path createNodeType( JcrNodeTypeTemplate nodeType,
170                                    Path parentPath ) throws InvalidNodeTypeDefinitionException {
171 
172         Name name = nameFrom(nodeType.getName());
173         Name[] supertypes = namesFrom(nodeType.declaredSupertypeNames());
174         boolean isAbstract = booleanFrom(nodeType.isAbstract(), false);
175         boolean hasOrderableChildNodes = booleanFrom(nodeType.hasOrderableChildNodes(), false);
176         boolean isMixin = booleanFrom(nodeType.isMixin(), false);
177         boolean isQueryable = true;
178         Name primaryItemName = nameFrom(nodeType.getPrimaryItemName());
179 
180         // Create the node for the node type ...
181         if (name == null) throw new InvalidNodeTypeDefinitionException(JcrI18n.invalidNodeTypeName.text());
182         Path path = pathFactory.create(parentPath, name);
183 
184         PropertyFactory factory = nodeType.getExecutionContext().getPropertyFactory();
185         destination.create(path,
186                            factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.NODE_TYPE),
187                            factory.create(JcrLexicon.SUPERTYPES, (Object[])supertypes),
188                            factory.create(JcrLexicon.IS_ABSTRACT, isAbstract),
189                            factory.create(JcrLexicon.HAS_ORDERABLE_CHILD_NODES, hasOrderableChildNodes),
190                            factory.create(JcrLexicon.IS_MIXIN, isMixin),
191                            factory.create(JcrLexicon.IS_QUERYABLE, isQueryable),
192                            factory.create(JcrLexicon.NODE_TYPE_NAME, name),
193                            factory.create(JcrLexicon.PRIMARY_ITEM_NAME, primaryItemName));
194 
195         for (PropertyDefinition propDefn : nodeType.getPropertyDefinitionTemplates()) {
196             createPropertyDefinition((JcrPropertyDefinitionTemplate)propDefn, path);
197         }
198 
199         for (NodeDefinition nodeDefn : nodeType.getNodeDefinitionTemplates()) {
200             createChildDefinition((JcrNodeDefinitionTemplate)nodeDefn, path);
201         }
202 
203         return path;
204     }
205 
206     /**
207      * Project the property definition from the given template onto the {@link #getNodeTypes() graph}.
208      * 
209      * @param propDefn
210      * @param parentPath
211      * @return the path to the newly created node
212      */
213     protected Path createPropertyDefinition( JcrPropertyDefinitionTemplate propDefn,
214                                              Path parentPath ) {
215         Name name = nameFrom(propDefn.getName());
216         String requiredType = PropertyType.nameFromValue(propDefn.getRequiredType()).toUpperCase();
217         Value[] rawValues = propDefn.getDefaultValues();
218         boolean multiple = booleanFrom(propDefn.isMultiple(), false);
219         boolean mandatory = booleanFrom(propDefn.isMandatory(), false);
220         boolean autoCreated = booleanFrom(propDefn.isAutoCreated(), false);
221         boolean isProtected = booleanFrom(propDefn.isProtected(), false);
222         String onParentVersion = OnParentVersionAction.nameFromValue(propDefn.getOnParentVersion()).toUpperCase();
223         // /*QueryOperator[] queryOperators =*/queryOperatorsFrom(propDefn, CndLexer.QUERY_OPERATORS);
224         // boolean isFullTextSearchable = booleanFrom(propDefn, CndLexer.IS_FULL_TEXT_SEARCHABLE, true);
225         // boolean isQueryOrderable = booleanFrom(propDefn, CndLexer.IS_QUERY_ORDERERABLE, true);
226         String[] valueConstraints = stringsFrom(propDefn.getValueConstraints());
227 
228         // Create the node for the node type ...
229         if (name == null) name = JcrNodeType.RESIDUAL_NAME;
230         Path path = pathFactory.create(parentPath, JcrLexicon.PROPERTY_DEFINITION);
231 
232         Object[] defaultValues;
233 
234         if (rawValues == null) {
235             defaultValues = new Object[0];
236         } else {
237             try {
238                 defaultValues = new Object[rawValues.length];
239                 for (int i = 0; i < rawValues.length; i++) {
240                     defaultValues[i] = rawValues[i].getString();
241                 }
242             } catch (RepositoryException re) {
243                 throw new IllegalStateException(re);
244             }
245         }
246 
247         PropertyFactory factory = propDefn.getExecutionContext().getPropertyFactory();
248         destination.create(path,
249                            factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.PROPERTY_DEFINITION),
250                            factory.create(JcrLexicon.REQUIRED_TYPE, requiredType),
251                            factory.create(JcrLexicon.DEFAULT_VALUES, defaultValues),
252                            factory.create(JcrLexicon.MULTIPLE, multiple),
253                            factory.create(JcrLexicon.MANDATORY, mandatory),
254                            factory.create(JcrLexicon.NAME, name),
255                            factory.create(JcrLexicon.AUTO_CREATED, autoCreated),
256                            factory.create(JcrLexicon.PROTECTED, isProtected),
257                            factory.create(JcrLexicon.ON_PARENT_VERSION, onParentVersion),
258                            // factory.create(ModeShapeLexicon.QUERY_OPERATORS, queryOperators),
259                            // factory.create(JcrLexicon.IS_FULL_TEXT_SEARCHABLE, isFullTextSearchable),
260                            // factory.create(JcrLexicon.IS_QUERY_ORDERABLE, isQueryOrderable),
261                            factory.create(JcrLexicon.VALUE_CONSTRAINTS, (Object[])valueConstraints));
262 
263         return path;
264     }
265 
266     /**
267      * Project the child node definition from the given template onto the {@link #getNodeTypes() graph}.
268      * 
269      * @param childDefn
270      * @param parentPath
271      * @return the path to the newly created node
272      */
273     protected Path createChildDefinition( JcrNodeDefinitionTemplate childDefn,
274                                           Path parentPath ) {
275         Name name = nameFrom(childDefn.getName());
276         Name[] requiredPrimaryTypes = namesFrom(childDefn.getRequiredPrimaryTypeNames());
277         Name defaultPrimaryType = nameFrom(childDefn.getDefaultPrimaryTypeName());
278         boolean mandatory = booleanFrom(childDefn.isMandatory(), false);
279         boolean autoCreated = booleanFrom(childDefn.isAutoCreated(), false);
280         boolean isProtected = booleanFrom(childDefn.isProtected(), false);
281         String onParentVersion = OnParentVersionAction.nameFromValue(childDefn.getOnParentVersion()).toUpperCase();
282         boolean sameNameSiblings = booleanFrom(childDefn.allowsSameNameSiblings(), false);
283 
284         // Create the node for the node type ...
285         if (name == null) name = JcrNodeType.RESIDUAL_NAME;
286         Path path = pathFactory.create(parentPath, JcrLexicon.CHILD_NODE_DEFINITION);
287 
288         PropertyFactory factory = childDefn.getExecutionContext().getPropertyFactory();
289         destination.create(path,
290                            factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.CHILD_NODE_DEFINITION),
291                            factory.create(JcrLexicon.REQUIRED_PRIMARY_TYPES, (Object[])requiredPrimaryTypes),
292                            factory.create(JcrLexicon.DEFAULT_PRIMARY_TYPE, defaultPrimaryType),
293                            factory.create(JcrLexicon.MANDATORY, mandatory),
294                            factory.create(JcrLexicon.NAME, name),
295                            factory.create(JcrLexicon.AUTO_CREATED, autoCreated),
296                            factory.create(JcrLexicon.PROTECTED, isProtected),
297                            factory.create(JcrLexicon.ON_PARENT_VERSION, onParentVersion),
298                            factory.create(JcrLexicon.SAME_NAME_SIBLINGS, sameNameSiblings));
299 
300         return path;
301     }
302 }