AbstractGriffonControllerActionManager.java
001 /*
002  * Copyright 2007-2013 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *      http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  */
015 
016 package org.codehaus.griffon.runtime.core.controller;
017 
018 import griffon.core.GriffonApplication;
019 import griffon.core.GriffonController;
020 import griffon.core.GriffonControllerClass;
021 import griffon.core.controller.GriffonControllerAction;
022 import griffon.core.controller.GriffonControllerActionManager;
023 import griffon.core.i18n.NoSuchMessageException;
024 import org.slf4j.Logger;
025 import org.slf4j.LoggerFactory;
026 
027 import java.lang.ref.WeakReference;
028 import java.util.Collections;
029 import java.util.LinkedHashMap;
030 import java.util.Map;
031 
032 import static griffon.util.GriffonApplicationUtils.isMacOSX;
033 import static griffon.util.GriffonNameUtils.*;
034 import static org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.castToBoolean;
035 
036 /**
037  @author Andres Almiray
038  @since 1.1.0
039  */
040 public abstract class AbstractGriffonControllerActionManager implements GriffonControllerActionManager {
041     private static final Logger LOG = LoggerFactory.getLogger(AbstractGriffonControllerActionManager.class);
042     private final ActionCache actionCache = new ActionCache();
043     private GriffonApplication app;
044 
045     protected AbstractGriffonControllerActionManager(GriffonApplication app) {
046         this.app = app;
047     }
048 
049     public GriffonApplication getApp() {
050         return app;
051     }
052 
053     public Map<String, GriffonControllerAction> actionsFor(GriffonController controller) {
054         if (controller == null) {
055             throw new IllegalArgumentException("controller parameter is null!");
056         }
057         Map<String, GriffonControllerAction> actions = actionCache.get(controller);
058         if (actions.isEmpty()) {
059             if (LOG.isTraceEnabled()) {
060                 LOG.trace("No actions defined for controller " + controller);
061             }
062         }
063         return actions;
064     }
065 
066     public GriffonControllerAction actionFor(GriffonController controller, String actionName) {
067         if (controller == null) {
068             throw new IllegalArgumentException("controller parameter is null!");
069         }
070         if (isBlank(actionName)) {
071             throw new IllegalArgumentException("actionName parameter is null!");
072         }
073 
074         return actionCache.get(controller).get(normalizeName(actionName));
075     }
076 
077     public void createActions(GriffonController controller) {
078         GriffonControllerClass griffonClass = (GriffonControllerClasscontroller.getGriffonClass();
079         for (String actionName : griffonClass.getActionNames()) {
080             GriffonControllerAction action = createAndConfigureAction(controller, actionName);
081             Map<String, GriffonControllerAction> actions = actionCache.get(controller);
082             if (actions.isEmpty()) {
083                 actions = new LinkedHashMap<String, GriffonControllerAction>();
084                 actionCache.set(controller, actions);
085             }
086             String actionKey = normalizeName(actionName);
087             if (LOG.isTraceEnabled()) {
088                 LOG.trace("Action for " + controller.getClass().getName() "." + actionName + " stored as " + actionKey);
089             }
090             actions.put(actionKey, action);
091         }
092     }
093 
094     protected GriffonControllerAction createAndConfigureAction(GriffonController controller, String actionName) {
095         GriffonControllerAction action = createControllerAction(controller, actionName);
096 
097         String normalizeNamed = capitalize(normalizeName(actionName));
098         String keyPrefix = controller.getClass().getName() ".action.";
099 
100         String rsActionName = msg(keyPrefix, normalizeNamed, "name", getNaturalName(normalizeNamed));
101         if (!isBlank(rsActionName)) {
102             if (LOG.isTraceEnabled()) {
103                 LOG.trace(keyPrefix + normalizeNamed + ".name = " + rsActionName);
104             }
105             action.setName(rsActionName);
106         }
107 
108         String rsAccelerator = msg(keyPrefix, normalizeNamed, "accelerator""");
109         if (!isBlank(rsAccelerator)) {
110             if (!isMacOSX() && rsAccelerator.contains("meta"&& !rsAccelerator.contains("ctrl")) {
111                 rsAccelerator = rsAccelerator.replace("meta""ctrl");
112             }
113             if (LOG.isTraceEnabled()) {
114                 LOG.trace(keyPrefix + normalizeNamed + ".accelerator = " + rsAccelerator);
115             }
116             action.setAccelerator(rsAccelerator);
117         }
118 
119         /*
120         String rsCommand = msg(keyPrefix, normalizeNamed, "command", "");
121         if (!isBlank(rsCommand)) {
122             if (LOG.isTraceEnabled()) {
123                 LOG.trace(keyPrefix + normalizeNamed + ".command = " + rsCommand);
124             }
125             action.setCommand(rsCommand);
126         }
127         */
128 
129         String rsShortDescription = msg(keyPrefix, normalizeNamed, "short_description""");
130         if (!isBlank(rsShortDescription)) {
131             if (LOG.isTraceEnabled()) {
132                 LOG.trace(keyPrefix + normalizeNamed + ".short_description = " + rsShortDescription);
133             }
134             action.setShortDescription(rsShortDescription);
135         }
136 
137         String rsLongDescription = msg(keyPrefix, normalizeNamed, "long_description""");
138         if (!isBlank(rsLongDescription)) {
139             if (LOG.isTraceEnabled()) {
140                 LOG.trace(keyPrefix + normalizeNamed + ".long_description = " + rsLongDescription);
141             }
142             action.setLongDescription(rsLongDescription);
143         }
144 
145         String rsMnemonic = msg(keyPrefix, normalizeNamed, "mnemonic""");
146         if (!isBlank(rsMnemonic)) {
147             if (LOG.isTraceEnabled()) {
148                 LOG.trace(keyPrefix + normalizeNamed + ".mnemonic = " + rsMnemonic);
149             }
150             action.setMnemonic(rsMnemonic);
151         }
152 
153         String rsSmallIcon = msg(keyPrefix, normalizeNamed, "small_icon""");
154         if (!isBlank(rsSmallIcon)) {
155             if (LOG.isTraceEnabled()) {
156                 LOG.trace(keyPrefix + normalizeNamed + ".small_icon = " + rsSmallIcon);
157             }
158             action.setSmallIcon(rsSmallIcon);
159         }
160 
161         String rsLargeIcon = msg(keyPrefix, normalizeNamed, "large_icon""");
162         if (!isBlank(rsLargeIcon)) {
163             if (LOG.isTraceEnabled()) {
164                 LOG.trace(keyPrefix + normalizeNamed + ".large_icon = " + rsLargeIcon);
165             }
166             action.setLargeIcon(rsLargeIcon);
167         }
168 
169         String rsEnabled = msg(keyPrefix, normalizeNamed, "enabled""true");
170         if (!isBlank(rsEnabled)) {
171             if (LOG.isTraceEnabled()) {
172                 LOG.trace(keyPrefix + normalizeNamed + ".enabled = " + rsEnabled);
173             }
174             action.setEnabled(castToBoolean(rsEnabled));
175         }
176 
177         String rsSelected = msg(keyPrefix, normalizeNamed, "selected""false");
178         if (!isBlank(rsSelected)) {
179             if (LOG.isTraceEnabled()) {
180                 LOG.trace(keyPrefix + normalizeNamed + ".selected = " + rsSelected);
181             }
182             action.setSelected(castToBoolean(rsSelected));
183         }
184 
185         return action;
186     }
187 
188     protected abstract GriffonControllerAction createControllerAction(GriffonController controller, String actionName);
189 
190     public String normalizeName(String actionName) {
191         if (actionName.endsWith(ACTION)) {
192             actionName = actionName.substring(0, actionName.length() - ACTION.length());
193         }
194         return uncapitalize(actionName);
195     }
196 
197     protected String msg(String key, String actionName, String subkey, String defaultValue) {
198         try {
199             return app.getMessage(key + actionName + "." + subkey);
200         catch (NoSuchMessageException nsme) {
201             return app.getMessage("application.action." + actionName + "." + subkey, defaultValue);
202         }
203     }
204 
205     private static class ActionCache {
206         private final Map<WeakReference<GriffonController>, Map<String, GriffonControllerAction>> cache = Collections.synchronizedMap(new LinkedHashMap<WeakReference<GriffonController>, Map<String, GriffonControllerAction>>());
207 
208         public Map<String, GriffonControllerAction> get(GriffonController controller) {
209             synchronized (cache) {
210                 for (Map.Entry<WeakReference<GriffonController>, Map<String, GriffonControllerAction>> entry : cache.entrySet()) {
211                     GriffonController test = entry.getKey().get();
212                     if (test == controller) {
213                         return entry.getValue();
214                     }
215                 }
216             }
217             return Collections.emptyMap();
218         }
219 
220         public void set(GriffonController controller, Map<String, GriffonControllerAction> actions) {
221             WeakReference<GriffonController> existingController = null;
222             synchronized (cache) {
223                 for (WeakReference<GriffonController> key : cache.keySet()) {
224                     if (key.get() == controller) {
225                         existingController = key;
226                         break;
227                     }
228                 }
229             }
230 
231             if (null != existingController) {
232                 cache.remove(existingController);
233             }
234 
235             cache.put(new WeakReference<GriffonController>(controller), actions);
236         }
237     }
238 }