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 021package org.granite.messaging.service; 022 023import java.util.Map; 024import java.util.Properties; 025 026import javax.naming.Context; 027import javax.naming.InitialContext; 028import javax.naming.NamingException; 029 030import org.granite.config.flex.Destination; 031import org.granite.context.GraniteContext; 032import org.granite.logging.Logger; 033import org.granite.util.XMap; 034 035import flex.messaging.messages.RemotingMessage; 036 037/** 038 * @author Franck WOLFF 039 */ 040public 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}