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 }