001/*
002 * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library 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 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 */
018
019package org.nuxeo.ecm.platform.ui.web.seam;
020
021import static org.jboss.seam.annotations.Install.FRAMEWORK;
022
023import java.util.HashMap;
024import java.util.Map;
025import java.util.concurrent.locks.ReentrantLock;
026
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.jboss.seam.ScopeType;
030import org.jboss.seam.annotations.Install;
031import org.jboss.seam.annotations.Name;
032import org.jboss.seam.annotations.Scope;
033import org.jboss.seam.annotations.intercept.BypassInterceptors;
034import org.jboss.seam.contexts.Contexts;
035import org.jboss.seam.core.providers.ServiceProvider;
036import org.nuxeo.ecm.core.api.CoreSession;
037import org.nuxeo.runtime.api.Framework;
038
039/**
040 * Provide simple extension to Seam injection system to be able to inject Nuxeo Services and Nuxeo Components inside
041 * Seam Beans
042 *
043 * @since 5.7.3
044 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a>
045 */
046@Scope(ScopeType.STATELESS)
047@Name(ServiceProvider.NAME)
048@Install(precedence = FRAMEWORK)
049@BypassInterceptors
050public class NuxeoRuntimeServiceProvider implements ServiceProvider {
051
052    private static final Log log = LogFactory.getLog(NuxeoRuntimeServiceProvider.class);
053
054    @SuppressWarnings("rawtypes")
055    protected static Map<String, Class> name2ServiceClassCache = new HashMap<String, Class>();
056
057    protected static ReentrantLock name2ServiceClassLock = new ReentrantLock();
058
059    @Override
060    @SuppressWarnings({ "rawtypes", "unchecked" })
061    public Object lookup(String name, Class type, boolean create) {
062
063        if (Framework.getRuntime() == null) {
064            return null;
065        }
066
067        if (type != null && type.isAssignableFrom(CoreSession.class)) {
068            // XXX return a CoreSession on the default repository ?
069            return null;
070        }
071
072        Object result = null;
073
074        // service loopkup
075        if (type != null) {
076            result = Framework.getLocalService(type);
077        }
078
079        // fallback on component lookup
080        if (result == null && name != null) {
081            if (!name.startsWith("org.jboss")) {
082                // remove lookup by component name
083                // result = Framework.getRuntime().getComponent(name);
084                // lookup service by short name
085                if (result == null) {
086                    result = findServiceByShortCut(name);
087                }
088            }
089        }
090        if (log.isDebugEnabled()) {
091            log.debug("Nuxeo Lookup => return " + result);
092        }
093        return result;
094
095    }
096
097    @SuppressWarnings({ "rawtypes", "unchecked" })
098    protected Object findServiceByShortCut(String name) {
099
100        if (!name2ServiceClassCache.containsKey(name)) {
101            Class klass = null;
102            name2ServiceClassLock.lock();
103            try {
104                for (String serviceClassName : Framework.getRuntime().getComponentManager().getServices()) {
105                    int p = serviceClassName.lastIndexOf('.');
106                    String fullClassName = serviceClassName;
107                    if (p > -1) {
108                        serviceClassName = serviceClassName.substring(p + 1);
109                    }
110                    if (name.equalsIgnoreCase(serviceClassName)) {
111                        try {
112                            klass = Thread.currentThread().getContextClassLoader().loadClass(fullClassName);
113                            if (log.isDebugEnabled()) {
114                                log.debug("Lookup for " + name + " resolved to service " + fullClassName);
115                            }
116                            break;
117                        } catch (ClassNotFoundException e) {
118                            log.error("Unable to load class for service " + fullClassName, e);
119                        }
120                    }
121                }
122                // NB : puts null if not found to avoid multiple lookups
123                name2ServiceClassCache.put(name, klass);
124            } finally {
125                name2ServiceClassLock.unlock();
126            }
127        }
128        Class serviceClass = name2ServiceClassCache.get(name);
129        Object result = null;
130        if (serviceClass != null) {
131            result = Framework.getLocalService(serviceClass);
132            if (result != null && Contexts.isEventContextActive()) {
133                // cache in Event scope
134                Contexts.getEventContext().set(name, result);
135            }
136        }
137        return result;
138    }
139
140}