001/**
002 *   GRANITE DATA SERVICES
003 *   Copyright (C) 2006-2014 GRANITE DATA SERVICES S.A.S.
004 *
005 *   This file is part of the Granite Data Services Platform.
006 *
007 *   Granite Data Services is free software; you can redistribute it and/or
008 *   modify it under the terms of the GNU Lesser General Public
009 *   License as published by the Free Software Foundation; either
010 *   version 2.1 of the License, or (at your option) any later version.
011 *
012 *   Granite Data Services is distributed in the hope that it will be useful,
013 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 *   General Public License for more details.
016 *
017 *   You should have received a copy of the GNU Lesser General Public
018 *   License along with this library; if not, write to the Free Software
019 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 *   USA, or see <http://www.gnu.org/licenses/>.
021 */
022package org.granite.messaging.service;
023
024import java.util.Map;
025import java.util.Properties;
026
027import javax.naming.Context;
028import javax.naming.InitialContext;
029import javax.naming.NamingException;
030
031import org.granite.config.flex.Destination;
032import org.granite.config.flex.ServicesConfig;
033import org.granite.context.GraniteContext;
034import org.granite.logging.Logger;
035import org.granite.util.XMap;
036
037import flex.messaging.messages.RemotingMessage;
038
039/**
040 * @author Franck WOLFF
041 */
042public class EjbServiceFactory extends ServiceFactory {
043
044    private static final Logger log = Logger.getLogger(EjbServiceFactory.class);
045
046    private Properties environment = null;
047    private transient InitialContext initialContext = null;
048    private String lookup = null;
049
050    public EjbServiceFactory() throws ServiceException {
051    }
052    
053    public synchronized Object lookup(String name) throws NamingException {
054        if (initialContext == null) {
055                if (environment == null || environment.isEmpty())
056                        initialContext = new InitialContext();
057                else
058                        initialContext = new InitialContext(environment);
059        }
060        return initialContext.lookup(name);
061    }
062    
063    public String getLookup() {
064        return lookup;
065    }
066
067    @Override
068    public void configure(XMap properties) throws ServiceException {
069        super.configure(properties);
070        
071        try {
072            environment = new Properties();
073            
074            for (XMap property : properties.getAll("initial-context-environment/property")) {
075                String name = property.get("name");
076                String value = property.get("value");
077                
078                if ("Context.PROVIDER_URL".equals(name))
079                        environment.put(Context.PROVIDER_URL, value);
080                else if ("Context.INITIAL_CONTEXT_FACTORY".equals(name))
081                        environment.put(Context.INITIAL_CONTEXT_FACTORY, value);
082                else if ("Context.URL_PKG_PREFIXES".equals(name))
083                        environment.put(Context.URL_PKG_PREFIXES, value);
084                else if ("Context.SECURITY_PRINCIPAL".equals(name))
085                        environment.put(Context.SECURITY_PRINCIPAL, value);
086                else if ("Context.SECURITY_CREDENTIALS".equals(name))
087                        environment.put(Context.SECURITY_CREDENTIALS, value);
088                else
089                        log.warn("Unknown InitialContext property: %s (ignored)", name);
090            }
091                
092            initialContext = new InitialContext(environment.size() > 0 ? environment : null);
093        } catch (Exception e) {
094                throw new ServiceException("Could not create InitialContext", e);
095        }
096        
097        lookup = properties.get("lookup");
098    }
099
100    @Override
101    public ServiceInvoker<?> getServiceInstance(RemotingMessage request) throws ServiceException {
102        GraniteContext context = GraniteContext.getCurrentInstance();
103
104        String destinationId = request.getDestination();
105        String key = getUniqueKey(destinationId);
106
107        EjbServiceInvoker invoker = null;
108
109        // Synchronize on unique key.
110        synchronized (key) {
111                // Retrieve cached instance.
112                invoker = (EjbServiceInvoker)context.getApplicationMap().get(key);
113                if (invoker == null) {
114                        Map<String, Object> sessionMap = context.getSessionMap(false);
115                        if (sessionMap != null)
116                                invoker = (EjbServiceInvoker)sessionMap.get(key);
117                }
118        }
119
120        // Not found, lookup and cache.
121        if (invoker == null) {
122            Destination destination = ((ServicesConfig)context.getServicesConfig()).findDestinationById(
123                request.getClass().getName(),
124                destinationId
125            );
126            invoker = new EjbServiceInvoker(destination, this);
127
128                Map<String, Object> cache = invoker.getMetadata().isStateful() ?
129                        context.getSessionMap(true) :
130                                context.getApplicationMap();
131
132                // Synchronize on unique key (put if absent)...
133            synchronized (key) {
134                        EjbServiceInvoker previousInvoker = (EjbServiceInvoker)cache.get(key);
135                if (previousInvoker != null)
136                        invoker = previousInvoker;
137                else
138                        cache.put(key, invoker);
139                        }
140        }
141        
142        return invoker;
143    }
144    
145    protected String getUniqueKey(String destinationId) {
146        return new StringBuilder(EjbServiceInvoker.class.getName().length() + 1 + destinationId.length())
147                .append(EjbServiceInvoker.class.getName())
148                .append('.')
149                .append(destinationId)
150                .toString()
151                .intern();
152    }
153    
154    public void removeFromCache(String destinationId) {
155        GraniteContext context = GraniteContext.getCurrentInstance();
156        String key = getUniqueKey(destinationId);
157        // Synchronize on unique key.
158        synchronized (key) {
159                context.getApplicationMap().remove(key);
160                Map<String, Object> sessionMap = context.getSessionMap(false);
161                if (sessionMap != null)
162                        context.getSessionMap().remove(key);
163        }
164    }
165
166    @Override
167    public String toString() {
168        return toString("\n  lookup: " + lookup);
169    }
170}