001 /* 002 * Copyright © 2008, 2012 Pedro Agulló Soliveres. 003 * 004 * This file is part of DirectJNgine. 005 * 006 * DirectJNgine is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU Lesser General Public License as published by 008 * the Free Software Foundation, either version 3 of the License. 009 * 010 * Commercial use is permitted to the extent that the code/component(s) 011 * do NOT become part of another Open Source or Commercially developed 012 * licensed development library or toolkit without explicit permission. 013 * 014 * DirectJNgine is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU Lesser General Public License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public License 020 * along with DirectJNgine. If not, see <http://www.gnu.org/licenses/>. 021 * 022 * This software uses the ExtJs library (http://extjs.com), which is 023 * distributed under the GPL v3 license (see http://extjs.com/license). 024 */ 025 026 package com.softwarementors.extjs.djn.servlet.ssm; 027 028 import java.util.HashMap; 029 import java.util.Map; 030 031 import javax.servlet.ServletContext; 032 import javax.servlet.http.HttpSession; 033 034 import org.apache.log4j.Logger; 035 036 import com.softwarementors.extjs.djn.api.RegisteredMethod; 037 import com.softwarementors.extjs.djn.router.dispatcher.DispatcherBase; 038 039 import edu.umd.cs.findbugs.annotations.NonNull; 040 041 public class SsmDispatcher extends DispatcherBase { 042 @NonNull private static final Map<Class<?>, Scope> methodScopeCache = 043 new HashMap<Class<?>, Scope>(); 044 045 @NonNull 046 private static final Logger logger = Logger.getLogger(SsmDispatcher.class); 047 048 @Override 049 protected Object getInvokeInstanceForNonStaticMethod(RegisteredMethod method) throws Exception { 050 assert method != null; 051 052 Class<?> instanceClass = method.getActionClass(); 053 Scope scope = methodScopeCache.get(instanceClass); 054 if( scope == null ) { 055 ActionScope methodScope = instanceClass.getAnnotation(ActionScope.class); 056 if( methodScope == null ) { 057 scope = Scope.STATELESS; 058 } 059 else { 060 scope = methodScope.scope(); 061 } 062 methodScopeCache.put( instanceClass, scope); 063 if( logger.isDebugEnabled() ) { 064 logger.debug( "Action class '" + instanceClass + "' will be instantiated with " + scope.toString() + "' scope." ); 065 } 066 } 067 068 assert scope != null; 069 Object result = getAction(method, scope); 070 return result; 071 } 072 073 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="SF_SWITCH_NO_DEFAULT", 074 justification="Missing a 'default' branch is not a problem with enums, given the appropriate compiler settings") 075 private Object getAction(RegisteredMethod method, Scope scope) throws Exception{ 076 Object result = null; 077 switch( scope ) { 078 case SESSION: 079 result = getSessionMethodInstance(method); 080 break; 081 case APPLICATION: 082 result = getApplicationMethodInstance(method); 083 break; 084 case STATELESS: 085 result = getStatelessMethodInstance(method); 086 break; 087 } 088 assert result != null; 089 return result; 090 } 091 092 private Object getStatelessMethodInstance(RegisteredMethod method) throws Exception { 093 assert method != null; 094 095 return createInvokeInstanceForMethodWithDefaultConstructor(method); 096 } 097 098 /* MUST be synchronized so that two competing threads do no instantiate and store two actions "at the same time". 099 */ 100 private synchronized Object getSessionMethodInstance(RegisteredMethod method) throws Exception { 101 assert method != null; 102 103 HttpSession context = WebContextManager.get().getSession(); 104 Object result = WebContextManager.get().getSessionScopedObject(method.getActionName()); 105 if( result == null ) { 106 String key = WebContext.getSessionScopedActionName(method.getActionName()); 107 result = createInvokeInstanceForMethodWithDefaultConstructor(method); 108 context.setAttribute(key, result); 109 } 110 return result; 111 } 112 113 /* MUST be synchronized so that two competing threads do no instantiate and store two actions "at the same time". 114 */ 115 private synchronized Object getApplicationMethodInstance(RegisteredMethod method) throws Exception { 116 assert method != null; 117 118 ServletContext context = WebContextManager.get().getServletContext(); 119 Object result = WebContextManager.get().getApplicationScopedObject(method.getActionName()); 120 if( result == null ) { 121 result = createInvokeInstanceForMethodWithDefaultConstructor(method); 122 String key = WebContext.getApplicationScopedActionName(method.getActionName()); 123 context.setAttribute(key, result); 124 } 125 return result; 126 } 127 128 }