001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    package org.crsh.jcr;
020    
021    import groovy.lang.GroovySystem;
022    import groovy.lang.MetaClassRegistry;
023    import org.crsh.jcr.groovy.NodeMetaClass;
024    import org.crsh.plugin.CRaSHPlugin;
025    
026    import javax.jcr.Node;
027    import java.beans.IntrospectionException;
028    import java.util.*;
029    import javax.jcr.Repository;
030    
031    public abstract class JCRPlugin<T extends JCRPlugin> extends CRaSHPlugin<T> {
032    
033      public static Repository findRepository(Map<String, String> properties) throws Exception {
034        for (JCRPlugin plugin : ServiceLoader.load(JCRPlugin.class)) {
035          Repository repository = plugin.getRepository(properties);
036          if (repository != null) {
037            return repository;
038          }
039        }
040        return null;
041      }
042    
043      public static Iterable<JCRPlugin> findRepositories() throws Exception {
044        return ServiceLoader.load(JCRPlugin.class);
045      }
046    
047      /** . */
048      private static final Collection<String> NODES = Arrays.asList(
049          "org.exoplatform.services.jcr.impl.core.NodeImpl",
050          "org.apache.jackrabbit.core.NodeImpl", "org.apache.jackrabbit.rmi.client.ClientNode",
051          "org.apache.jackrabbit.rmi.server.ServerNode");
052    
053      /** . */
054      private static final Object LOCK = new Object();
055    
056      /** . */
057      private static boolean integrated = false;
058    
059      public Collection<String> getNodeClassNames() {
060        return NODES;
061      }
062      
063      public abstract Repository getRepository(Map<String, String> properties) throws Exception;
064    
065      public abstract String getName();
066    
067      public abstract String getDisplayName();
068    
069      public abstract String getUsage();
070    
071      @Override
072      public void init() {
073        // Force integration of node meta class
074        NodeMetaClass.setup();
075        synchronized (LOCK) {
076          if (!integrated) {
077            try {
078              MetaClassRegistry registry = GroovySystem.getMetaClassRegistry();
079              Collection<Class<? extends Node>> nodes = loadAvailablesNodeImplementations(getNodeClassNames());
080              for (Class<? extends Node> nodeClass : nodes) {
081                registerNodeImplementation(registry, nodeClass);
082              }
083            } catch (IntrospectionException e) {
084              throw new RuntimeException(e);
085            }
086          }
087          integrated = true;
088        }
089      }
090    
091      private Collection<Class<? extends Node>> loadAvailablesNodeImplementations(
092          Collection<String> classNames) {
093        List<Class<? extends Node>> classes = new ArrayList<Class<? extends Node>>(classNames.size());
094        for (String className : classNames) {
095          Class<? extends Node> nodeClass = loadNodeImplementation(className);
096          if (nodeClass != null) {
097            classes.add(nodeClass);
098          }
099        }
100        return classes;
101      }
102    
103      private Class<? extends Node> loadNodeImplementation(String className) {
104        try {
105          return (Class<? extends Node>) Thread.currentThread().getContextClassLoader().loadClass(
106              className);
107        } catch (ClassNotFoundException e) {
108          return null;
109        }
110      }
111    
112      private void registerNodeImplementation(MetaClassRegistry registry,
113          Class<? extends Node> nodeClass) throws IntrospectionException {
114        NodeMetaClass mc2 = new NodeMetaClass(registry, nodeClass);
115        mc2.initialize();
116        registry.setMetaClass(nodeClass, mc2);
117      }
118    }