001    /**
002     *   GRANITE DATA SERVICES
003     *   Copyright (C) 2006-2013 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     */
022    package org.granite.messaging.service;
023    
024    import java.util.Map;
025    import java.util.Properties;
026    
027    import javax.naming.Context;
028    import javax.naming.InitialContext;
029    import javax.naming.NamingException;
030    
031    import org.granite.config.flex.Destination;
032    import org.granite.context.GraniteContext;
033    import org.granite.logging.Logger;
034    import org.granite.util.XMap;
035    
036    import flex.messaging.messages.RemotingMessage;
037    
038    /**
039     * @author Franck WOLFF
040     */
041    public class EjbServiceFactory extends ServiceFactory {
042    
043        private static final Logger log = Logger.getLogger(EjbServiceFactory.class);
044    
045        private Properties environment = null;
046        private transient InitialContext initialContext = null;
047        private String lookup = null;
048    
049        public EjbServiceFactory() throws ServiceException {
050        }
051        
052        public synchronized Object lookup(String name) throws NamingException {
053            if (initialContext == null) {
054                    if (environment == null || environment.isEmpty())
055                            initialContext = new InitialContext();
056                    else
057                            initialContext = new InitialContext(environment);
058            }
059            return initialContext.lookup(name);
060        }
061        
062        public String getLookup() {
063            return lookup;
064        }
065    
066        @Override
067        public void configure(XMap properties) throws ServiceException {
068            super.configure(properties);
069            
070            try {
071                environment = new Properties();
072                
073                for (XMap property : properties.getAll("initial-context-environment/property")) {
074                    String name = property.get("name");
075                    String value = property.get("value");
076                    
077                    if ("Context.PROVIDER_URL".equals(name))
078                            environment.put(Context.PROVIDER_URL, value);
079                    else if ("Context.INITIAL_CONTEXT_FACTORY".equals(name))
080                            environment.put(Context.INITIAL_CONTEXT_FACTORY, value);
081                    else if ("Context.URL_PKG_PREFIXES".equals(name))
082                            environment.put(Context.URL_PKG_PREFIXES, value);
083                    else if ("Context.SECURITY_PRINCIPAL".equals(name))
084                            environment.put(Context.SECURITY_PRINCIPAL, value);
085                    else if ("Context.SECURITY_CREDENTIALS".equals(name))
086                            environment.put(Context.SECURITY_CREDENTIALS, value);
087                    else
088                            log.warn("Unknown InitialContext property: %s (ignored)", name);
089                }
090                    
091                initialContext = new InitialContext(environment.size() > 0 ? environment : null);
092            } catch (Exception e) {
093                    throw new ServiceException("Could not create InitialContext", e);
094            }
095            
096            lookup = properties.get("lookup");
097        }
098    
099        @Override
100        public ServiceInvoker<?> getServiceInstance(RemotingMessage request) throws ServiceException {
101            GraniteContext context = GraniteContext.getCurrentInstance();
102    
103            String destinationId = request.getDestination();
104            String key = getUniqueKey(destinationId);
105    
106            EjbServiceInvoker invoker = null;
107    
108            // Synchronize on unique key.
109            synchronized (key) {
110                    // Retrieve cached instance.
111                    invoker = (EjbServiceInvoker)context.getApplicationMap().get(key);
112                    if (invoker == null) {
113                            Map<String, Object> sessionMap = context.getSessionMap(false);
114                            if (sessionMap != null)
115                                    invoker = (EjbServiceInvoker)sessionMap.get(key);
116                    }
117            }
118    
119            // Not found, lookup and cache.
120            if (invoker == null) {
121                Destination destination = context.getServicesConfig().findDestinationById(
122                    request.getClass().getName(),
123                    destinationId
124                );
125                invoker = new EjbServiceInvoker(destination, this);
126    
127                    Map<String, Object> cache = invoker.getMetadata().isStateful() ?
128                            context.getSessionMap(true) :
129                                    context.getApplicationMap();
130    
131                    // Synchronize on unique key (put if absent)...
132                synchronized (key) {
133                            EjbServiceInvoker previousInvoker = (EjbServiceInvoker)cache.get(key);
134                    if (previousInvoker != null)
135                            invoker = previousInvoker;
136                    else
137                            cache.put(key, invoker);
138                            }
139            }
140            
141            return invoker;
142        }
143        
144        protected String getUniqueKey(String destinationId) {
145            return new StringBuilder(EjbServiceInvoker.class.getName().length() + 1 + destinationId.length())
146                    .append(EjbServiceInvoker.class.getName())
147                    .append('.')
148                    .append(destinationId)
149                    .toString()
150                    .intern();
151        }
152        
153        public void removeFromCache(String destinationId) {
154            GraniteContext context = GraniteContext.getCurrentInstance();
155            String key = getUniqueKey(destinationId);
156            // Synchronize on unique key.
157            synchronized (key) {
158                    context.getApplicationMap().remove(key);
159                    Map<String, Object> sessionMap = context.getSessionMap(false);
160                    if (sessionMap != null)
161                            context.getSessionMap().remove(key);
162            }
163        }
164    
165        @Override
166        public String toString() {
167            return toString("\n  lookup: " + lookup);
168        }
169    }