View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.prefs.impl;
18  
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.LinkedList;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Vector;
27  
28  import org.apache.jetspeed.cache.CacheElement;
29  import org.apache.jetspeed.cache.DistributedCacheObject;
30  import org.apache.jetspeed.cache.JetspeedCache;
31  import org.apache.jetspeed.components.dao.InitablePersistenceBrokerDaoSupport;
32  import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
33  import org.apache.jetspeed.om.common.portlet.MutablePortletEntity;
34  import org.apache.jetspeed.prefs.FailedToCreateNodeException;
35  import org.apache.jetspeed.prefs.NodeAlreadyExistsException;
36  import org.apache.jetspeed.prefs.NodeDoesNotExistException;
37  import org.apache.jetspeed.prefs.PreferencesProvider;
38  import org.apache.jetspeed.prefs.om.Node;
39  import org.apache.jetspeed.prefs.om.Property;
40  import org.apache.jetspeed.prefs.om.impl.NodeImpl;
41  import org.apache.jetspeed.prefs.om.impl.PropertyImpl;
42  import org.apache.ojb.broker.query.Criteria;
43  import org.apache.ojb.broker.query.Query;
44  import org.apache.ojb.broker.query.QueryFactory;
45  
46  /***
47   * <p>
48   * PersistenceBrokerPreferencesProvider
49   * </p>
50   * 
51   * @author <a href="mailto:weaver@apache.org">Scott T. Weaver </a>
52   * @version $Id: PersistenceBrokerPreferencesProvider.java 605797 2007-12-20 03:39:09Z woonsan $
53   */
54  public class PersistenceBrokerPreferencesProvider extends InitablePersistenceBrokerDaoSupport implements
55          PreferencesProvider
56  {
57      
58      private static class NodeCache implements DistributedCacheObject
59      {
60          /*** The serial uid. */
61          private static final long serialVersionUID = 1853381807991868844L;
62          NodeImplProxy node = null;
63          String key = null;;
64          Collection children = null;;
65  
66          public NodeCache(NodeImplProxy node)
67          {
68              // System.out.println(this.getClass().getName() + "-" + "NodeCache (node)" + node.getFullPath());
69              this.node = node;
70              this.key = node.getFullPath() + "-" + node.getNodeType();
71          }
72  
73          public NodeCache(String fullpath, int type)
74          {
75              // System.out.println(this.getClass().getName() + "-" + "NodeCache - fullpath=" + fullpath);
76              this.key = fullpath + "-" + type;
77          }
78  
79          public boolean isChildrenLoaded()
80          {
81              // System.out.println(this.getClass().getName() + "-" + "isChildrenLoaded");
82              return children != null;
83          }
84  
85  
86  
87          public NodeImplProxy getNode()
88          {
89              // System.out.println(this.getClass().getName() + "-" + "getNode=" + node.getFullPath());
90              return node;
91          }
92  
93          public void setNode(NodeImplProxy node)
94          {
95              // System.out.println(this.getClass().getName() + "-" + "setFullpath=" + node.getFullPath());
96              this.node = node;
97          }
98  
99          public Collection getChildren()
100         {
101             // System.out.println(this.getClass().getName() + "-" + "getCHildren=" );
102             return children;
103         }
104 
105         public void setChildren(Collection children)
106         {
107             // System.out.println(this.getClass().getName() + "-" + "setChildren=" );
108             this.children = children;
109         }
110 
111         public boolean equals(Object obj)
112         {
113             if (obj != null && obj instanceof NodeCache)
114             {
115                 NodeCache other = (NodeCache) obj;
116                 return getKey().equals(other.getKey());
117             }
118             return false;
119         }
120 
121         public int hashCode()
122         {
123             return getKey().hashCode();
124         }
125         
126         public String getCacheKey()
127         {
128             return getKey();
129         }
130 
131 		public String getKey()
132 		{
133 			return key;
134 		}
135 
136 		
137 	    public void notifyChange(int action)
138 	    {
139 
140 	    	switch (action)
141 	    	{
142 	    		case CacheElement.ActionAdded:
143 //					System.out.println("CacheObject Added =" + this.getKey());
144 	    			break;
145 	    		case CacheElement.ActionChanged:
146 //					System.out.println("CacheObject Changed =" + this.getKey());
147 					if (this.node != null)
148 						this.node.invalidate();
149 	    			break;
150 	    		case CacheElement.ActionRemoved:
151 //					System.out.println("CacheObject Removed =" + this.getKey());
152 					if (this.node != null)
153 						this.node.invalidate();
154 	    			break;
155 	    		case CacheElement.ActionEvicted:
156 //					System.out.println("CacheObject Evicted =" + this.getKey());
157 					if (this.node != null)
158 						this.node.invalidate();
159 	    			break;
160 	    		case CacheElement.ActionExpired:
161 //					System.out.println("CacheObject Expired =" + this.getKey());
162 					if (this.node != null)
163 						this.node.invalidate();
164 	    			break;
165 	    		default:
166 					System.out.println("CacheObject - UNKOWN OPRERATION =" + this.getKey());
167 	    			return;
168 	    	}
169 	    	return;
170 		}
171     }
172 
173     private JetspeedCache preferenceCache;
174     private List preloadedApplications;
175     private boolean preloadEntities = false;
176     
177     /***
178      * @param repositoryPath
179      *            Location of repository mapping file. Must be available within the classpath.
180      * @throws ClassNotFoundException
181      *             if the <code>prefsFactoryImpl</code> argument does not reperesent a Class that exists in the
182      *             current classPath.
183      */
184     public PersistenceBrokerPreferencesProvider(String repositoryPath)
185             throws ClassNotFoundException
186     {
187         super(repositoryPath);
188         NodeImplProxy.setProvider(this);
189         this.preloadedApplications = new LinkedList();
190     }
191 
192     
193     /***
194      * @param repository
195      *            Location of repository mapping file. Must be available within the classpath.
196      * @param prefsFactoryImpl
197      *            <code>java.util.prefs.PreferencesFactory</code> implementation to use.
198      * @param enablePropertyManager
199      *            Whether or not we chould be suing the property manager.
200      * @throws ClassNotFoundException
201      *             if the <code>prefsFactoryImpl</code> argument does not reperesent a Class that exists in the
202      *             current classPath.
203      */
204     public PersistenceBrokerPreferencesProvider(String repositoryPath, JetspeedCache preferenceCache)
205             throws ClassNotFoundException
206     {
207         this(repositoryPath);
208         this.preferenceCache = preferenceCache;
209     }
210 
211     public PersistenceBrokerPreferencesProvider(String repositoryPath, JetspeedCache preferenceCache, List apps, boolean preloadEntities)
212     throws ClassNotFoundException
213     {
214         this(repositoryPath);
215         this.preferenceCache = preferenceCache;
216         this.preloadedApplications = apps;
217         this.preloadEntities = preloadEntities;
218     }
219     
220     protected void addToCache(NodeCache content)
221     {
222         CacheElement cachedElement = preferenceCache.createElement(content.getCacheKey(), content);
223         cachedElement.setTimeToIdleSeconds(preferenceCache.getTimeToIdleSeconds());
224         cachedElement.setTimeToLiveSeconds(preferenceCache.getTimeToLiveSeconds());
225         preferenceCache.put(cachedElement);        
226     }    
227   
228     private NodeCache getNode(String cacheKey)
229     {
230     	CacheElement cachedElement = preferenceCache.get(cacheKey);
231         if (cachedElement != null)
232          return (NodeCache)cachedElement.getContent();  
233         return null;
234     }
235 
236     
237     public Node getNode(String fullPath, int nodeType) throws NodeDoesNotExistException
238     {
239         NodeCache key = new NodeCache(fullPath, nodeType);
240         NodeCache hit = getNode(key.getCacheKey());
241         if (hit != null)
242         {
243             return hit.getNode();
244         }
245 
246         Criteria c = new Criteria();
247         c.addEqualTo("fullPath", fullPath);
248         c.addEqualTo("nodeType", new Integer(nodeType));
249         Query query = QueryFactory.newQuery(NodeImpl.class, c);
250 
251         Node nodeObj = (Node) getPersistenceBrokerTemplate().getObjectByQuery(query);
252         if (null != nodeObj)
253         {
254         	NodeImplProxy proxy = new NodeImplProxy(nodeObj);
255             addToCache(new NodeCache(proxy));
256             return proxy;
257            
258         }
259         else
260         {
261             throw new NodeDoesNotExistException("No node of type " + nodeType + "found at path: " + fullPath);
262         }
263     }
264     /***
265      * @see org.apache.jetspeed.prefs.PreferencesProvider#getNode(java.lang.String, int)
266      */
267     public void redoNode(NodeImplProxy proxy, String fullPath, int nodeType) throws NodeDoesNotExistException
268     {
269         
270         Criteria c = new Criteria();
271         c.addEqualTo("fullPath", fullPath);
272         c.addEqualTo("nodeType", new Integer(nodeType));
273         Query query = QueryFactory.newQuery(NodeImpl.class, c);
274 
275         Node nodeObj = (Node) getPersistenceBrokerTemplate().getObjectByQuery(query);
276         if (null != nodeObj)
277         {
278         	proxy.setNode(nodeObj);
279         	NodeCache cn = new NodeCache(nodeObj.getFullPath(), nodeObj.getNodeType());
280         	cn.setNode(proxy);
281             addToCache(cn);
282         }
283         else
284         {
285             throw new NodeDoesNotExistException("No node of type " + nodeType + "found at path: " + fullPath);
286         }
287     }
288 
289     /***
290      * @see org.apache.jetspeed.prefs.PreferencesProvider#nodeExists(java.lang.String, int)
291      */
292     public boolean nodeExists(String fullPath, int nodeType)
293     {
294         NodeCache key = new NodeCache(fullPath, nodeType);
295         if (preferenceCache.isKeyInCache(key))
296         	return true;
297         Criteria c = new Criteria();
298         c.addEqualTo("fullPath", fullPath);
299         c.addEqualTo("nodeType", new Integer(nodeType));
300         Query query = QueryFactory.newQuery(NodeImpl.class, c);
301 
302         Node nodeObj = (Node) getPersistenceBrokerTemplate().getObjectByQuery(query);
303         if (null != nodeObj)
304         {
305         	NodeImplProxy proxy = new NodeImplProxy(nodeObj);
306             addToCache(new NodeCache(proxy));
307             return true;
308         }
309         else
310         {
311             return false;
312         }
313     }
314 
315     /***
316      * @see org.apache.jetspeed.prefs.PreferencesProvider#createNode(org.apache.jetspeed.prefs.om.Node, java.lang.String, int, java.lang.String)
317      */
318     public Node createNode(Node parent, String nodeName, int nodeType, String fullPath)
319             throws FailedToCreateNodeException, NodeAlreadyExistsException
320     {
321         if (nodeExists(fullPath, nodeType))
322         {
323             throw new NodeAlreadyExistsException("Node of type " + nodeType + " already exists at path " + fullPath);
324         }
325         else
326         {
327             Long parentNodeId = null;
328             if (null != parent)
329             {
330                 parentNodeId = new Long(parent.getNodeId());
331             }
332 
333             Node nodeObj = new NodeImpl(parentNodeId, nodeName, nodeType, fullPath);
334 
335             try
336             {
337                 getPersistenceBrokerTemplate().store(nodeObj);
338             	NodeImplProxy proxy = new NodeImplProxy(nodeObj);
339                 addToCache(new NodeCache(proxy));
340                 return proxy;
341             }
342             catch (Exception e)
343             {
344                 throw new FailedToCreateNodeException("Failed to create node of type " + nodeType + " for the path "
345                         + fullPath + ".  " + e.toString(), e);
346             }
347 
348         }
349     }
350   
351     /***
352      * @see org.apache.jetspeed.prefs.PreferencesProvider#getChildren(org.apache.jetspeed.prefs.om.Node)
353      */
354     public Collection getChildren(Node parentNode)
355     {
356         NodeCache key = new NodeCache(parentNode.getFullPath(), parentNode.getNodeType());
357 
358         NodeCache hit = getNode(key.getCacheKey());
359         if (hit == null)
360         {
361         	NodeImplProxy proxy = new NodeImplProxy(parentNode);
362             hit = new NodeCache(proxy);
363             addToCache(hit);
364         }
365         if (hit.isChildrenLoaded())
366         {
367             return resolveChildren(hit.getChildren());
368         }
369 
370         Criteria c = new Criteria();
371         c.addEqualTo("parentNodeId", new Long(parentNode.getNodeId()));
372         Query query = QueryFactory.newQuery(NodeImpl.class, c);
373         Collection children = getPersistenceBrokerTemplate().getCollectionByQuery(query);
374         hit.setChildren(cacheChildren(children));
375         // null or not
376         return children;
377     }
378 
379     
380     private Collection resolveChildren(Collection children)
381     {
382     	if (children == null)
383     		return null;
384     	try
385     	{
386 	    	Iterator it = children.iterator();
387 	    	Vector v = new Vector();
388 	    	while (it.hasNext())
389 	    	{
390 	    		String s = (String) it.next();
391 	    		NodeCache hit = getNode(s);
392 	    		if (hit != null)
393                 {
394 	    			v.add(hit.getNode());
395                 }
396                 else
397                 {
398                     int index = s.lastIndexOf("-");
399                     if (index > 0)
400                     {
401                         String fullPath = s.substring(0, index);
402                         int type = Integer.parseInt(s.substring(index + 1));
403                         Node node = getNode(fullPath, type);
404                         if (node != null)
405                         {
406                             v.add(node);
407                         }
408                     }
409                 }
410 	    	}
411 	    	return v;
412     	}
413     	catch (Exception e)
414     	{
415     		e.printStackTrace();
416     		return null;
417     	}
418     }
419 
420     
421     private Collection cacheChildren(Collection children)
422     {
423     	Iterator it = children.iterator();
424     	Vector v = new Vector();
425     	while (it.hasNext())
426     	{
427     		   Node key = (Node)it.next();	
428     	       NodeCache nodeKey = new NodeCache(key.getFullPath(),key.getNodeType());
429     	       NodeCache hit = getNode(nodeKey.getCacheKey());
430    	           if (hit == null)
431    	           {
432    	    		   NodeImplProxy proxy = new NodeImplProxy(key);
433    	    		   nodeKey.setNode(proxy);
434    	    	       addToCache(nodeKey);
435    	    	       hit= nodeKey;
436    	           }
437     	        v.add(hit.getCacheKey());
438     	}
439     	return v;
440     }
441 
442     /***
443      * @see org.apache.jetspeed.prefs.PreferencesProvider#storeNode(org.apache.jetspeed.prefs.om.Node)
444      */
445     public void storeNode(Node node)
446     {
447     	NodeImplProxy hit = null;
448     	if (node instanceof NodeImplProxy)
449     	{
450     		hit = (NodeImplProxy)node;
451     	}
452     	else
453     	{
454     		//System.out.println("WARNING!!!!STORE NODE!!!!!!!!!!!! -  Illegal Node element passed");
455     		hit = new NodeImplProxy(node);
456     	}
457     	
458         NodeCache key = new NodeCache(hit);
459         getPersistenceBrokerTemplate().store(hit.getNode()); // avoid racing condition with the db and with cluster notification
460         											// do the db first
461         preferenceCache.remove(key.getCacheKey()); // not sure we should actually do that, could also just update the node
462         addToCache(key);
463     }
464 
465     /***
466      * @see org.apache.jetspeed.prefs.PreferencesProvider#removeNode(org.apache.jetspeed.prefs.om.Node, org.apache.jetspeed.prefs.om.Node)
467      */
468     public void removeNode(Node parentNode, Node node)
469     {
470     	NodeImplProxy hit = null;
471     	NodeImplProxy parentHit = null;
472 
473     	if (node instanceof NodeImplProxy)
474     	{
475     		getPersistenceBrokerTemplate().delete(((NodeImplProxy)node).getNode());  //avoid race conditions - do this first    
476     	}
477     	else
478     		getPersistenceBrokerTemplate().delete(node);  //avoid race conditions - do this first    
479     		
480     	if (node instanceof NodeImplProxy)
481     	{
482     		hit = (NodeImplProxy)node;
483     	}
484     	else
485     	{
486     		//System.out.println("WARNING!!!!REMOVE NODE!!!!!!!!!!!! -  Illegal Node element passed");
487     		hit = new NodeImplProxy(node);
488     	}
489         NodeCache key = new NodeCache(hit);
490         preferenceCache.remove(key.getCacheKey());
491         if ( parentNode != null )
492         {
493         	if (parentNode instanceof NodeImplProxy)
494         	{
495         		parentHit = (NodeImplProxy)parentNode;
496         	}
497         	else
498         	{
499         		//System.out.println("WARNING!!!!REMOVE NODE!!!!!!!!!!!! -  Illegal Node element passed");
500         		parentHit = new NodeImplProxy(parentNode);
501         	}
502         	NodeCache parentKey = new NodeCache(parentHit);
503         	parentKey = getNode(parentKey.getCacheKey());
504             if ( parentKey != null && parentKey.isChildrenLoaded() )
505             {
506             	parentKey.getChildren().remove(key.getCacheKey());
507             }
508         }
509     }
510     
511     /***
512      * @see org.apache.jetspeed.prefs.PreferencesProvider#lookupPreference(java.lang.String, java.lang.String, java.lang.String)
513      */
514     public Collection lookupPreference(String nodeName, String propertyName, String propertyValue)
515     {
516         Criteria c = new Criteria();
517         if (nodeName != null)
518         {
519             c.addEqualTo("nodeName", nodeName);
520         }
521         if (propertyName != null)
522         {
523             c.addEqualTo("nodeProperties.propertyName", propertyName);
524         }
525         if (propertyValue != null)
526         {
527             c.addEqualTo("nodeProperties.propertyValue", propertyValue);
528         }
529         Query query = QueryFactory.newQuery(NodeImpl.class, c);
530         Collection children = getPersistenceBrokerTemplate().getCollectionByQuery(query);
531         Collection proxied = new ArrayList();
532         Iterator iter = children.iterator();
533         while (iter.hasNext())
534         {
535             NodeImpl node = (NodeImpl)iter.next();              
536             NodeCache key = new NodeCache(node.getFullPath(), node.getNodeType());
537             NodeCache hit = getNode(key.getCacheKey());
538             if (hit == null)
539             {
540                 NodeImplProxy proxy = new NodeImplProxy(node);
541                 addToCache(new NodeCache(proxy));
542                 proxied.add(proxy);
543             }            
544             else
545             {
546                 proxied.add(hit.getNode());
547             }
548         }
549         return proxied;       
550     }
551     
552     public Property createProperty(Node node, String name, Object value)
553     {
554         return new PropertyImpl(node.getNodeId(), name, value);
555     }
556 
557     public void init() throws Exception
558     {
559         super.init();
560         Iterator apps = this.preloadedApplications.iterator();
561         while (apps.hasNext())
562         {
563             String appName = (String)apps.next();
564             preloadApplicationPreferences(appName);
565         }
566         if (preloadEntities)
567             preloadAllEntities();
568     }
569     
570     public void preloadApplicationPreferences(String portletApplicationName) throws NodeDoesNotExistException
571     {
572         String portletDefPrefPath = "/" + MutablePortletApplication.PREFS_ROOT + "/" + portletApplicationName + "/";
573 //        + PortletDefinitionComposite.PORTLETS_PREFS_ROOT + "/" + portlet.getName() + "/"
574 //        + MutablePortletApplication.PORTLET_PREFERENCES_ROOT;
575 //        NodeCache key = new NodeCache(portletDefPrefPath, 1);
576 //        NodeCache hit = getNode(key.getCacheKey());
577 //        if (hit != null)
578 //        {
579 //            return 1;
580 //            //return hit.getNode();
581 //        }        
582         long start = System.currentTimeMillis();        
583         int count = loadNodeAndAllChildren(portletDefPrefPath);
584         long elapsed = System.currentTimeMillis() - start;
585         System.out.println("++++ PREFS:PA loaded " + count + " pref nodes for app " + portletDefPrefPath + " in " + elapsed + " milliseconds.");
586     }
587     
588     protected int loadNodeAndAllChildren(String path)
589     {
590         int count = 0;
591         NodeCache root = null;
592         Criteria c = new Criteria();
593         c.addLike("fullPath", path + "%");
594         //c.addOrderBy("fullPath");
595         Query query = QueryFactory.newQuery(NodeImpl.class, c);
596         Collection result = getPersistenceBrokerTemplate().getCollectionByQuery(query);
597         // TODO: ensure that we always get the first node back first
598         if (result == null || result.isEmpty())
599         {
600             return count;           
601         }
602         Iterator ri = result.iterator();
603         if (ri.hasNext())
604         {
605             Node n = (Node)ri.next();
606             NodeImplProxy proxy = new NodeImplProxy(n);
607             root = new NodeCache(proxy);
608             addToCache(root);
609             count++;
610         }
611         else
612         {
613             return count;        
614         }
615         Map parents = new HashMap();
616         parents.put(new Long(root.getNode().getNodeId()), root);
617         while (ri.hasNext())
618         {
619             // build children and subchildren
620             Node subNode = (Node)ri.next();
621             //System.out.println("*** Preloading: " + subNode.getFullPath());
622             // add to current node
623             NodeCache nodeKey = new NodeCache(subNode.getFullPath(), subNode.getNodeType());
624             NodeCache lookup = getNode(nodeKey.getCacheKey());
625             if (lookup == null)
626             {
627                 NodeImplProxy proxy = new NodeImplProxy(subNode);
628                 nodeKey.setNode(proxy);
629                 addToCache(nodeKey);
630                 lookup = nodeKey;
631             }
632             NodeCache parent = (NodeCache)parents.get(subNode.getParentNodeId());
633             if (parent != null)
634             {
635                 if (parent.getChildren() == null)
636                     parent.setChildren(new ArrayList());
637                 parent.getChildren().add(lookup.getCacheKey());
638                 count += parent.getChildren().size();
639             }
640             parents.put(new Long(subNode.getNodeId()), lookup);
641             count++;
642         }         
643         return count;
644     }
645     
646     public void preloadAllEntities() throws NodeDoesNotExistException
647     {
648         String entitiesRoot = "/" + MutablePortletEntity.PORTLET_ENTITY_ROOT + "/";
649         long start = System.currentTimeMillis();        
650         int count = loadNodeAndAllChildren(entitiesRoot);
651         long elapsed = System.currentTimeMillis() - start;
652         System.out.println("++++ PREFS:ENTITIES loaded " + count + " total entity pref nodes in " + elapsed + " milliseconds.");
653     }
654     
655 }