001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.prefs.impl;
018:
019: import java.util.ArrayList;
020: import java.util.Collection;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.LinkedList;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Vector;
027:
028: import org.apache.jetspeed.cache.CacheElement;
029: import org.apache.jetspeed.cache.DistributedCacheObject;
030: import org.apache.jetspeed.cache.JetspeedCache;
031: import org.apache.jetspeed.components.dao.InitablePersistenceBrokerDaoSupport;
032: import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
033: import org.apache.jetspeed.om.common.portlet.MutablePortletEntity;
034: import org.apache.jetspeed.prefs.FailedToCreateNodeException;
035: import org.apache.jetspeed.prefs.NodeAlreadyExistsException;
036: import org.apache.jetspeed.prefs.NodeDoesNotExistException;
037: import org.apache.jetspeed.prefs.PreferencesProvider;
038: import org.apache.jetspeed.prefs.om.Node;
039: import org.apache.jetspeed.prefs.om.Property;
040: import org.apache.jetspeed.prefs.om.impl.NodeImpl;
041: import org.apache.jetspeed.prefs.om.impl.PropertyImpl;
042: import org.apache.ojb.broker.query.Criteria;
043: import org.apache.ojb.broker.query.Query;
044: import org.apache.ojb.broker.query.QueryFactory;
045:
046: /**
047: * <p>
048: * PersistenceBrokerPreferencesProvider
049: * </p>
050: *
051: * @author <a href="mailto:weaver@apache.org">Scott T. Weaver </a>
052: * @version $Id: PersistenceBrokerPreferencesProvider.java 605797 2007-12-20 03:39:09Z woonsan $
053: */
054: public class PersistenceBrokerPreferencesProvider extends
055: InitablePersistenceBrokerDaoSupport implements
056: PreferencesProvider {
057:
058: private static class NodeCache implements DistributedCacheObject {
059: /** The serial uid. */
060: private static final long serialVersionUID = 1853381807991868844L;
061: NodeImplProxy node = null;
062: String key = null;;
063: Collection children = null;;
064:
065: public NodeCache(NodeImplProxy node) {
066: // System.out.println(this.getClass().getName() + "-" + "NodeCache (node)" + node.getFullPath());
067: this .node = node;
068: this .key = node.getFullPath() + "-" + node.getNodeType();
069: }
070:
071: public NodeCache(String fullpath, int type) {
072: // System.out.println(this.getClass().getName() + "-" + "NodeCache - fullpath=" + fullpath);
073: this .key = fullpath + "-" + type;
074: }
075:
076: public boolean isChildrenLoaded() {
077: // System.out.println(this.getClass().getName() + "-" + "isChildrenLoaded");
078: return children != null;
079: }
080:
081: public NodeImplProxy getNode() {
082: // System.out.println(this.getClass().getName() + "-" + "getNode=" + node.getFullPath());
083: return node;
084: }
085:
086: public void setNode(NodeImplProxy node) {
087: // System.out.println(this.getClass().getName() + "-" + "setFullpath=" + node.getFullPath());
088: this .node = node;
089: }
090:
091: public Collection getChildren() {
092: // System.out.println(this.getClass().getName() + "-" + "getCHildren=" );
093: return children;
094: }
095:
096: public void setChildren(Collection children) {
097: // System.out.println(this.getClass().getName() + "-" + "setChildren=" );
098: this .children = children;
099: }
100:
101: public boolean equals(Object obj) {
102: if (obj != null && obj instanceof NodeCache) {
103: NodeCache other = (NodeCache) obj;
104: return getKey().equals(other.getKey());
105: }
106: return false;
107: }
108:
109: public int hashCode() {
110: return getKey().hashCode();
111: }
112:
113: public String getCacheKey() {
114: return getKey();
115: }
116:
117: public String getKey() {
118: return key;
119: }
120:
121: public void notifyChange(int action) {
122:
123: switch (action) {
124: case CacheElement.ActionAdded:
125: // System.out.println("CacheObject Added =" + this.getKey());
126: break;
127: case CacheElement.ActionChanged:
128: // System.out.println("CacheObject Changed =" + this.getKey());
129: if (this .node != null)
130: this .node.invalidate();
131: break;
132: case CacheElement.ActionRemoved:
133: // System.out.println("CacheObject Removed =" + this.getKey());
134: if (this .node != null)
135: this .node.invalidate();
136: break;
137: case CacheElement.ActionEvicted:
138: // System.out.println("CacheObject Evicted =" + this.getKey());
139: if (this .node != null)
140: this .node.invalidate();
141: break;
142: case CacheElement.ActionExpired:
143: // System.out.println("CacheObject Expired =" + this.getKey());
144: if (this .node != null)
145: this .node.invalidate();
146: break;
147: default:
148: System.out.println("CacheObject - UNKOWN OPRERATION ="
149: + this .getKey());
150: return;
151: }
152: return;
153: }
154: }
155:
156: private JetspeedCache preferenceCache;
157: private List preloadedApplications;
158: private boolean preloadEntities = false;
159:
160: /**
161: * @param repositoryPath
162: * Location of repository mapping file. Must be available within the classpath.
163: * @throws ClassNotFoundException
164: * if the <code>prefsFactoryImpl</code> argument does not reperesent a Class that exists in the
165: * current classPath.
166: */
167: public PersistenceBrokerPreferencesProvider(String repositoryPath)
168: throws ClassNotFoundException {
169: super (repositoryPath);
170: NodeImplProxy.setProvider(this );
171: this .preloadedApplications = new LinkedList();
172: }
173:
174: /**
175: * @param repository
176: * Location of repository mapping file. Must be available within the classpath.
177: * @param prefsFactoryImpl
178: * <code>java.util.prefs.PreferencesFactory</code> implementation to use.
179: * @param enablePropertyManager
180: * Whether or not we chould be suing the property manager.
181: * @throws ClassNotFoundException
182: * if the <code>prefsFactoryImpl</code> argument does not reperesent a Class that exists in the
183: * current classPath.
184: */
185: public PersistenceBrokerPreferencesProvider(String repositoryPath,
186: JetspeedCache preferenceCache)
187: throws ClassNotFoundException {
188: this (repositoryPath);
189: this .preferenceCache = preferenceCache;
190: }
191:
192: public PersistenceBrokerPreferencesProvider(String repositoryPath,
193: JetspeedCache preferenceCache, List apps,
194: boolean preloadEntities) throws ClassNotFoundException {
195: this (repositoryPath);
196: this .preferenceCache = preferenceCache;
197: this .preloadedApplications = apps;
198: this .preloadEntities = preloadEntities;
199: }
200:
201: protected void addToCache(NodeCache content) {
202: CacheElement cachedElement = preferenceCache.createElement(
203: content.getCacheKey(), content);
204: cachedElement.setTimeToIdleSeconds(preferenceCache
205: .getTimeToIdleSeconds());
206: cachedElement.setTimeToLiveSeconds(preferenceCache
207: .getTimeToLiveSeconds());
208: preferenceCache.put(cachedElement);
209: }
210:
211: private NodeCache getNode(String cacheKey) {
212: CacheElement cachedElement = preferenceCache.get(cacheKey);
213: if (cachedElement != null)
214: return (NodeCache) cachedElement.getContent();
215: return null;
216: }
217:
218: public Node getNode(String fullPath, int nodeType)
219: throws NodeDoesNotExistException {
220: NodeCache key = new NodeCache(fullPath, nodeType);
221: NodeCache hit = getNode(key.getCacheKey());
222: if (hit != null) {
223: return hit.getNode();
224: }
225:
226: Criteria c = new Criteria();
227: c.addEqualTo("fullPath", fullPath);
228: c.addEqualTo("nodeType", new Integer(nodeType));
229: Query query = QueryFactory.newQuery(NodeImpl.class, c);
230:
231: Node nodeObj = (Node) getPersistenceBrokerTemplate()
232: .getObjectByQuery(query);
233: if (null != nodeObj) {
234: NodeImplProxy proxy = new NodeImplProxy(nodeObj);
235: addToCache(new NodeCache(proxy));
236: return proxy;
237:
238: } else {
239: throw new NodeDoesNotExistException("No node of type "
240: + nodeType + "found at path: " + fullPath);
241: }
242: }
243:
244: /**
245: * @see org.apache.jetspeed.prefs.PreferencesProvider#getNode(java.lang.String, int)
246: */
247: public void redoNode(NodeImplProxy proxy, String fullPath,
248: int nodeType) throws NodeDoesNotExistException {
249:
250: Criteria c = new Criteria();
251: c.addEqualTo("fullPath", fullPath);
252: c.addEqualTo("nodeType", new Integer(nodeType));
253: Query query = QueryFactory.newQuery(NodeImpl.class, c);
254:
255: Node nodeObj = (Node) getPersistenceBrokerTemplate()
256: .getObjectByQuery(query);
257: if (null != nodeObj) {
258: proxy.setNode(nodeObj);
259: NodeCache cn = new NodeCache(nodeObj.getFullPath(), nodeObj
260: .getNodeType());
261: cn.setNode(proxy);
262: addToCache(cn);
263: } else {
264: throw new NodeDoesNotExistException("No node of type "
265: + nodeType + "found at path: " + fullPath);
266: }
267: }
268:
269: /**
270: * @see org.apache.jetspeed.prefs.PreferencesProvider#nodeExists(java.lang.String, int)
271: */
272: public boolean nodeExists(String fullPath, int nodeType) {
273: NodeCache key = new NodeCache(fullPath, nodeType);
274: if (preferenceCache.isKeyInCache(key))
275: return true;
276: Criteria c = new Criteria();
277: c.addEqualTo("fullPath", fullPath);
278: c.addEqualTo("nodeType", new Integer(nodeType));
279: Query query = QueryFactory.newQuery(NodeImpl.class, c);
280:
281: Node nodeObj = (Node) getPersistenceBrokerTemplate()
282: .getObjectByQuery(query);
283: if (null != nodeObj) {
284: NodeImplProxy proxy = new NodeImplProxy(nodeObj);
285: addToCache(new NodeCache(proxy));
286: return true;
287: } else {
288: return false;
289: }
290: }
291:
292: /**
293: * @see org.apache.jetspeed.prefs.PreferencesProvider#createNode(org.apache.jetspeed.prefs.om.Node, java.lang.String, int, java.lang.String)
294: */
295: public Node createNode(Node parent, String nodeName, int nodeType,
296: String fullPath) throws FailedToCreateNodeException,
297: NodeAlreadyExistsException {
298: if (nodeExists(fullPath, nodeType)) {
299: throw new NodeAlreadyExistsException("Node of type "
300: + nodeType + " already exists at path " + fullPath);
301: } else {
302: Long parentNodeId = null;
303: if (null != parent) {
304: parentNodeId = new Long(parent.getNodeId());
305: }
306:
307: Node nodeObj = new NodeImpl(parentNodeId, nodeName,
308: nodeType, fullPath);
309:
310: try {
311: getPersistenceBrokerTemplate().store(nodeObj);
312: NodeImplProxy proxy = new NodeImplProxy(nodeObj);
313: addToCache(new NodeCache(proxy));
314: return proxy;
315: } catch (Exception e) {
316: throw new FailedToCreateNodeException(
317: "Failed to create node of type " + nodeType
318: + " for the path " + fullPath + ". "
319: + e.toString(), e);
320: }
321:
322: }
323: }
324:
325: /**
326: * @see org.apache.jetspeed.prefs.PreferencesProvider#getChildren(org.apache.jetspeed.prefs.om.Node)
327: */
328: public Collection getChildren(Node parentNode) {
329: NodeCache key = new NodeCache(parentNode.getFullPath(),
330: parentNode.getNodeType());
331:
332: NodeCache hit = getNode(key.getCacheKey());
333: if (hit == null) {
334: NodeImplProxy proxy = new NodeImplProxy(parentNode);
335: hit = new NodeCache(proxy);
336: addToCache(hit);
337: }
338: if (hit.isChildrenLoaded()) {
339: return resolveChildren(hit.getChildren());
340: }
341:
342: Criteria c = new Criteria();
343: c.addEqualTo("parentNodeId", new Long(parentNode.getNodeId()));
344: Query query = QueryFactory.newQuery(NodeImpl.class, c);
345: Collection children = getPersistenceBrokerTemplate()
346: .getCollectionByQuery(query);
347: hit.setChildren(cacheChildren(children));
348: // null or not
349: return children;
350: }
351:
352: private Collection resolveChildren(Collection children) {
353: if (children == null)
354: return null;
355: try {
356: Iterator it = children.iterator();
357: Vector v = new Vector();
358: while (it.hasNext()) {
359: String s = (String) it.next();
360: NodeCache hit = getNode(s);
361: if (hit != null) {
362: v.add(hit.getNode());
363: } else {
364: int index = s.lastIndexOf("-");
365: if (index > 0) {
366: String fullPath = s.substring(0, index);
367: int type = Integer.parseInt(s
368: .substring(index + 1));
369: Node node = getNode(fullPath, type);
370: if (node != null) {
371: v.add(node);
372: }
373: }
374: }
375: }
376: return v;
377: } catch (Exception e) {
378: e.printStackTrace();
379: return null;
380: }
381: }
382:
383: private Collection cacheChildren(Collection children) {
384: Iterator it = children.iterator();
385: Vector v = new Vector();
386: while (it.hasNext()) {
387: Node key = (Node) it.next();
388: NodeCache nodeKey = new NodeCache(key.getFullPath(), key
389: .getNodeType());
390: NodeCache hit = getNode(nodeKey.getCacheKey());
391: if (hit == null) {
392: NodeImplProxy proxy = new NodeImplProxy(key);
393: nodeKey.setNode(proxy);
394: addToCache(nodeKey);
395: hit = nodeKey;
396: }
397: v.add(hit.getCacheKey());
398: }
399: return v;
400: }
401:
402: /**
403: * @see org.apache.jetspeed.prefs.PreferencesProvider#storeNode(org.apache.jetspeed.prefs.om.Node)
404: */
405: public void storeNode(Node node) {
406: NodeImplProxy hit = null;
407: if (node instanceof NodeImplProxy) {
408: hit = (NodeImplProxy) node;
409: } else {
410: //System.out.println("WARNING!!!!STORE NODE!!!!!!!!!!!! - Illegal Node element passed");
411: hit = new NodeImplProxy(node);
412: }
413:
414: NodeCache key = new NodeCache(hit);
415: getPersistenceBrokerTemplate().store(hit.getNode()); // avoid racing condition with the db and with cluster notification
416: // do the db first
417: preferenceCache.remove(key.getCacheKey()); // not sure we should actually do that, could also just update the node
418: addToCache(key);
419: }
420:
421: /**
422: * @see org.apache.jetspeed.prefs.PreferencesProvider#removeNode(org.apache.jetspeed.prefs.om.Node, org.apache.jetspeed.prefs.om.Node)
423: */
424: public void removeNode(Node parentNode, Node node) {
425: NodeImplProxy hit = null;
426: NodeImplProxy parentHit = null;
427:
428: if (node instanceof NodeImplProxy) {
429: getPersistenceBrokerTemplate().delete(
430: ((NodeImplProxy) node).getNode()); //avoid race conditions - do this first
431: } else
432: getPersistenceBrokerTemplate().delete(node); //avoid race conditions - do this first
433:
434: if (node instanceof NodeImplProxy) {
435: hit = (NodeImplProxy) node;
436: } else {
437: //System.out.println("WARNING!!!!REMOVE NODE!!!!!!!!!!!! - Illegal Node element passed");
438: hit = new NodeImplProxy(node);
439: }
440: NodeCache key = new NodeCache(hit);
441: preferenceCache.remove(key.getCacheKey());
442: if (parentNode != null) {
443: if (parentNode instanceof NodeImplProxy) {
444: parentHit = (NodeImplProxy) parentNode;
445: } else {
446: //System.out.println("WARNING!!!!REMOVE NODE!!!!!!!!!!!! - Illegal Node element passed");
447: parentHit = new NodeImplProxy(parentNode);
448: }
449: NodeCache parentKey = new NodeCache(parentHit);
450: parentKey = getNode(parentKey.getCacheKey());
451: if (parentKey != null && parentKey.isChildrenLoaded()) {
452: parentKey.getChildren().remove(key.getCacheKey());
453: }
454: }
455: }
456:
457: /**
458: * @see org.apache.jetspeed.prefs.PreferencesProvider#lookupPreference(java.lang.String, java.lang.String, java.lang.String)
459: */
460: public Collection lookupPreference(String nodeName,
461: String propertyName, String propertyValue) {
462: Criteria c = new Criteria();
463: if (nodeName != null) {
464: c.addEqualTo("nodeName", nodeName);
465: }
466: if (propertyName != null) {
467: c.addEqualTo("nodeProperties.propertyName", propertyName);
468: }
469: if (propertyValue != null) {
470: c.addEqualTo("nodeProperties.propertyValue", propertyValue);
471: }
472: Query query = QueryFactory.newQuery(NodeImpl.class, c);
473: Collection children = getPersistenceBrokerTemplate()
474: .getCollectionByQuery(query);
475: Collection proxied = new ArrayList();
476: Iterator iter = children.iterator();
477: while (iter.hasNext()) {
478: NodeImpl node = (NodeImpl) iter.next();
479: NodeCache key = new NodeCache(node.getFullPath(), node
480: .getNodeType());
481: NodeCache hit = getNode(key.getCacheKey());
482: if (hit == null) {
483: NodeImplProxy proxy = new NodeImplProxy(node);
484: addToCache(new NodeCache(proxy));
485: proxied.add(proxy);
486: } else {
487: proxied.add(hit.getNode());
488: }
489: }
490: return proxied;
491: }
492:
493: public Property createProperty(Node node, String name, Object value) {
494: return new PropertyImpl(node.getNodeId(), name, value);
495: }
496:
497: public void init() throws Exception {
498: super .init();
499: Iterator apps = this .preloadedApplications.iterator();
500: while (apps.hasNext()) {
501: String appName = (String) apps.next();
502: preloadApplicationPreferences(appName);
503: }
504: if (preloadEntities)
505: preloadAllEntities();
506: }
507:
508: public void preloadApplicationPreferences(
509: String portletApplicationName)
510: throws NodeDoesNotExistException {
511: String portletDefPrefPath = "/"
512: + MutablePortletApplication.PREFS_ROOT + "/"
513: + portletApplicationName + "/";
514: // + PortletDefinitionComposite.PORTLETS_PREFS_ROOT + "/" + portlet.getName() + "/"
515: // + MutablePortletApplication.PORTLET_PREFERENCES_ROOT;
516: // NodeCache key = new NodeCache(portletDefPrefPath, 1);
517: // NodeCache hit = getNode(key.getCacheKey());
518: // if (hit != null)
519: // {
520: // return 1;
521: // //return hit.getNode();
522: // }
523: long start = System.currentTimeMillis();
524: int count = loadNodeAndAllChildren(portletDefPrefPath);
525: long elapsed = System.currentTimeMillis() - start;
526: System.out.println("++++ PREFS:PA loaded " + count
527: + " pref nodes for app " + portletDefPrefPath + " in "
528: + elapsed + " milliseconds.");
529: }
530:
531: protected int loadNodeAndAllChildren(String path) {
532: int count = 0;
533: NodeCache root = null;
534: Criteria c = new Criteria();
535: c.addLike("fullPath", path + "%");
536: //c.addOrderBy("fullPath");
537: Query query = QueryFactory.newQuery(NodeImpl.class, c);
538: Collection result = getPersistenceBrokerTemplate()
539: .getCollectionByQuery(query);
540: // TODO: ensure that we always get the first node back first
541: if (result == null || result.isEmpty()) {
542: return count;
543: }
544: Iterator ri = result.iterator();
545: if (ri.hasNext()) {
546: Node n = (Node) ri.next();
547: NodeImplProxy proxy = new NodeImplProxy(n);
548: root = new NodeCache(proxy);
549: addToCache(root);
550: count++;
551: } else {
552: return count;
553: }
554: Map parents = new HashMap();
555: parents.put(new Long(root.getNode().getNodeId()), root);
556: while (ri.hasNext()) {
557: // build children and subchildren
558: Node subNode = (Node) ri.next();
559: //System.out.println("*** Preloading: " + subNode.getFullPath());
560: // add to current node
561: NodeCache nodeKey = new NodeCache(subNode.getFullPath(),
562: subNode.getNodeType());
563: NodeCache lookup = getNode(nodeKey.getCacheKey());
564: if (lookup == null) {
565: NodeImplProxy proxy = new NodeImplProxy(subNode);
566: nodeKey.setNode(proxy);
567: addToCache(nodeKey);
568: lookup = nodeKey;
569: }
570: NodeCache parent = (NodeCache) parents.get(subNode
571: .getParentNodeId());
572: if (parent != null) {
573: if (parent.getChildren() == null)
574: parent.setChildren(new ArrayList());
575: parent.getChildren().add(lookup.getCacheKey());
576: count += parent.getChildren().size();
577: }
578: parents.put(new Long(subNode.getNodeId()), lookup);
579: count++;
580: }
581: return count;
582: }
583:
584: public void preloadAllEntities() throws NodeDoesNotExistException {
585: String entitiesRoot = "/"
586: + MutablePortletEntity.PORTLET_ENTITY_ROOT + "/";
587: long start = System.currentTimeMillis();
588: int count = loadNodeAndAllChildren(entitiesRoot);
589: long elapsed = System.currentTimeMillis() - start;
590: System.out.println("++++ PREFS:ENTITIES loaded " + count
591: + " total entity pref nodes in " + elapsed
592: + " milliseconds.");
593: }
594:
595: }
|