001/*
002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 *
019 */
020
021package org.nuxeo.ecm.platform.ui.web.seam;
022
023import static org.jboss.seam.annotations.Install.FRAMEWORK;
024
025import java.util.HashMap;
026import java.util.Map;
027import java.util.concurrent.locks.ReentrantLock;
028
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031import org.jboss.seam.ScopeType;
032import org.jboss.seam.annotations.Install;
033import org.jboss.seam.annotations.Name;
034import org.jboss.seam.annotations.Scope;
035import org.jboss.seam.annotations.intercept.BypassInterceptors;
036import org.jboss.seam.contexts.Contexts;
037import org.jboss.seam.core.providers.ServiceProvider;
038import org.nuxeo.ecm.core.api.CoreSession;
039import org.nuxeo.runtime.api.Framework;
040
041/**
042 * Provide simple extension to Seam injection system to be able to inject Nuxeo Services and Nuxeo Components inside
043 * Seam Beans
044 *
045 * @since 5.7.3
046 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a>
047 */
048@Scope(ScopeType.STATELESS)
049@Name(ServiceProvider.NAME)
050@Install(precedence = FRAMEWORK)
051@BypassInterceptors
052public class NuxeoRuntimeServiceProvider implements ServiceProvider {
053
054    private static final Log log = LogFactory.getLog(NuxeoRuntimeServiceProvider.class);
055
056    @SuppressWarnings("rawtypes")
057    protected static Map<String, Class> name2ServiceClassCache = new HashMap<String, Class>();
058
059    protected static ReentrantLock name2ServiceClassLock = new ReentrantLock();
060
061    @Override
062    @SuppressWarnings({ "rawtypes", "unchecked" })
063    public Object lookup(String name, Class type, boolean create) {
064
065        if (Framework.getRuntime() == null) {
066            return null;
067        }
068
069        if (type != null && type.isAssignableFrom(CoreSession.class)) {
070            // XXX return a CoreSession on the default repository ?
071            return null;
072        }
073
074        Object result = null;
075
076        // service loopkup
077        if (type != null) {
078            result = Framework.getLocalService(type);
079        }
080
081        // fallback on component lookup
082        if (result == null && name != null) {
083            if (!name.startsWith("org.jboss")) {
084                // remove lookup by component name
085                // result = Framework.getRuntime().getComponent(name);
086                // lookup service by short name
087                if (result == null) {
088                    result = findServiceByShortCut(name);
089                }
090            }
091        }
092        if (log.isDebugEnabled()) {
093            log.debug("Nuxeo Lookup => return " + result);
094        }
095        return result;
096
097    }
098
099    @SuppressWarnings({ "rawtypes", "unchecked" })
100    protected Object findServiceByShortCut(String name) {
101
102        if (!name2ServiceClassCache.containsKey(name)) {
103            Class klass = null;
104            name2ServiceClassLock.lock();
105            try {
106                for (String serviceClassName : Framework.getRuntime().getComponentManager().getServices()) {
107                    int p = serviceClassName.lastIndexOf('.');
108                    String fullClassName = serviceClassName;
109                    if (p > -1) {
110                        serviceClassName = serviceClassName.substring(p + 1);
111                    }
112                    if (name.equalsIgnoreCase(serviceClassName)) {
113                        try {
114                            klass = Thread.currentThread().getContextClassLoader().loadClass(fullClassName);
115                            if (log.isDebugEnabled()) {
116                                log.debug("Lookup for " + name + " resolved to service " + fullClassName);
117                            }
118                            break;
119                        } catch (ClassNotFoundException e) {
120                            log.error("Unable to load class for service " + fullClassName, e);
121                        }
122                    }
123                }
124                // NB : puts null if not found to avoid multiple lookups
125                name2ServiceClassCache.put(name, klass);
126            } finally {
127                name2ServiceClassLock.unlock();
128            }
129        }
130        Class serviceClass = name2ServiceClassCache.get(name);
131        Object result = null;
132        if (serviceClass != null) {
133            result = Framework.getLocalService(serviceClass);
134            if (result != null && Contexts.isEventContextActive()) {
135                // cache in Event scope
136                Contexts.getEventContext().set(name, result);
137            }
138        }
139        return result;
140    }
141
142}