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 }