001 /* 002 * Copyright © 2008, 2009 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.RegisteredAction; 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> actionScopeCache = 043 new HashMap<Class<?>, Scope>(); 044 045 @NonNull 046 private static final Logger logger = Logger.getLogger(SsmDispatcher.class); 047 048 @Override 049 protected Object getActionInstance(RegisteredAction action) { 050 assert action != null; 051 052 Class<?> instanceClass = action.getActionClass(); 053 Scope scope = actionScopeCache.get(instanceClass); 054 if( scope == null ) { 055 ActionScope actionScope = instanceClass.getAnnotation(ActionScope.class); 056 if( actionScope == null ) { 057 scope = Scope.STATELESS; 058 } 059 else { 060 scope = actionScope.scope(); 061 } 062 actionScopeCache.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(action, 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(RegisteredAction action, Scope scope) { 076 Object result = null; 077 switch( scope ) { 078 case SESSION: 079 result = getSessionActionInstance(action); 080 break; 081 case APPLICATION: 082 result = getApplicationActionInstance(action); 083 break; 084 case STATELESS: 085 result = getStatelessActionInstance(action); 086 break; 087 } 088 assert result != null; 089 return result; 090 } 091 092 private Object getStatelessActionInstance(RegisteredAction action) { 093 assert action != null; 094 095 return createActionInstance(action); 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 getSessionActionInstance(RegisteredAction action) { 101 assert action != null; 102 103 HttpSession context = WebContextManager.get().getSession(); 104 Object result = WebContextManager.get().getSessionScopedObject(action.getName()); 105 if( result == null ) { 106 String key = WebContext.getSessionScopedActionName(action.getName()); 107 result = createActionInstance(action); 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 getApplicationActionInstance(RegisteredAction action) { 116 assert action != null; 117 118 ServletContext context = WebContextManager.get().getServletContext(); 119 Object result = WebContextManager.get().getApplicationScopedObject(action.getName()); 120 if( result == null ) { 121 result = createActionInstance(action); 122 String key = WebContext.getApplicationScopedActionName(action.getName()); 123 context.setAttribute(key, result); 124 } 125 return result; 126 } 127 128 }