View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.util.documentserializer;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.krad.util.KRADConstants;
20  
21  import java.util.StringTokenizer;
22  
23  /**
24   * This is a implementation of a trie/prefix tree of that contains metadata about property serializability
25   * during the document serialization process.
26   *
27   */
28  public class PropertySerializerTrie {
29      private static final String PROPERTY_NAME_COMPONENT_SEPARATOR = ".";
30      private PropertySerializerTrieNode rootNode;
31  
32      public PropertySerializerTrie() {
33          rootNode = new PropertySerializerTrieNode(KRADConstants.EMPTY_STRING, KRADConstants.EMPTY_STRING);
34      }
35  
36      /**
37       * Registers a new serializable property so that all of its primitives are serialized.  All nesting properties
38       * will be serialized only to render open/close tags to maintain consistency with the document structure, unless
39       * they are registered as well.
40       *
41       * For example, if only property "document.a.b" is registered, then the XML will look like the following:
42       *
43       * <document>
44       *     <a>
45       *         <b>
46       *             <primitiveOfB>valueOfPrimitive</primitiveOfB>
47       *         </b>
48       *     </a>
49       * </document>
50       *
51       * That is, primitives of "document" and "document.a" will not be serialized unless those property strings are registered.
52       *
53       * @param propertyName
54       * @param setPropertySerializabilityToObjectAndAllPrimitivesForAll
55       */
56      public void addSerializablePropertyName(String propertyName, boolean setPropertySerializabilityToObjectAndAllPrimitivesForAll) {
57          if (propertyName == null) {
58              throw new IllegalArgumentException("Null attribute name specified");
59          }
60          if (StringUtils.isBlank(propertyName)) {
61              rootNode.setPropertySerializabilityToObjectAndAllPrimitives();
62          }
63          else {
64              StringTokenizer tok = new StringTokenizer(propertyName, PROPERTY_NAME_COMPONENT_SEPARATOR, false);
65              StringBuilder buf = new StringBuilder();
66  
67              if(setPropertySerializabilityToObjectAndAllPrimitivesForAll)
68              	rootNode.setPropertySerializabilityToObjectAndAllPrimitives();
69  
70              PropertySerializerTrieNode currentNode = rootNode;
71              while (tok.hasMoreTokens()) {
72                  String attributeNameComponent = tok.nextToken();
73                  validateAttributeNameComponent(attributeNameComponent);
74  
75                  buf.append(attributeNameComponent);
76  
77                  // create a new node or retrieve existing node for this name component
78                  PropertySerializerTrieNode childNode = currentNode.getChildNode(attributeNameComponent);
79                  if (childNode == null) {
80                      childNode = new PropertySerializerTrieNode(buf.toString(), attributeNameComponent);
81                      currentNode.addChildNode(childNode);
82                  }
83  
84                  if (tok.hasMoreTokens()) {
85                      buf.append(PROPERTY_NAME_COMPONENT_SEPARATOR);
86                  }
87                  currentNode = childNode;
88                  if(setPropertySerializabilityToObjectAndAllPrimitivesForAll)
89                  	currentNode.setPropertySerializabilityToObjectAndAllPrimitives();
90              }
91  
92              currentNode.setPropertySerializabilityToObjectAndAllPrimitives();
93          }
94      }
95  
96      /**
97       * Retrieves the metadata about the given property name
98       *
99       * @param propertyName
100      * @return
101      */
102     public PropertySerializabilityMetadata getPropertySerializabilityMetadata(String propertyName) {
103         if (propertyName == null) {
104             throw new IllegalArgumentException("Null attribute name specified");
105         }
106         if (StringUtils.isBlank(propertyName)) {
107             return rootNode;
108         }
109         else {
110             StringTokenizer tok = new StringTokenizer(propertyName, PROPERTY_NAME_COMPONENT_SEPARATOR, false);
111 
112             PropertySerializerTrieNode currentNode = rootNode;
113             while (tok.hasMoreTokens()) {
114                 String attributeNameComponent = tok.nextToken();
115                 validateAttributeNameComponent(attributeNameComponent);
116 
117                 // retrieve the child node for this name component
118                 PropertySerializerTrieNode childNode = currentNode.getChildNode(attributeNameComponent);
119                 if (childNode == null) {
120                     // we didn't find a child node, so we know that something wasn't added with the prefix we're processing
121                     return null;
122                 }
123                 else {
124                     // keep going until we hit the last token, at which case we'll get out of this loop
125                     currentNode = childNode;
126                 }
127             }
128             return currentNode;
129         }
130     }
131 
132     /**
133      * Returns the root node of the trie
134      *
135      * @return
136      */
137     public PropertySerializabilityMetadata getRootPropertySerializibilityMetadata() {
138         return rootNode;
139     }
140 
141     protected void validateAttributeNameComponent(String attributeNameComponent) {
142         if (StringUtils.isBlank(attributeNameComponent)) {
143             throw new IllegalArgumentException("Blank attribute name component specified");
144         }
145     }
146 }