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