001/* 002 * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 * $Id: ActionRegistry.java 20637 2007-06-17 12:37:03Z sfermigier $ 018 */ 019 020package org.nuxeo.ecm.platform.actions; 021 022import java.io.Serializable; 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.Collections; 026import java.util.HashMap; 027import java.util.LinkedList; 028import java.util.List; 029import java.util.Map; 030 031import org.apache.commons.lang.StringUtils; 032import org.apache.commons.logging.Log; 033import org.apache.commons.logging.LogFactory; 034 035/** 036 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 037 */ 038public class ActionRegistry implements Serializable { 039 040 private static final Log log = LogFactory.getLog(ActionRegistry.class); 041 042 private static final long serialVersionUID = 8425627293154848041L; 043 044 private final Map<String, Action> actions; 045 046 private final Map<String, List<String>> categories; 047 048 private List<TypeCompatibility> typeCategoryRelations; 049 050 public ActionRegistry() { 051 actions = new HashMap<String, Action>(); 052 categories = new HashMap<String, List<String>>(); 053 typeCategoryRelations = new ArrayList<TypeCompatibility>(); 054 } 055 056 public synchronized void addAction(Action action) { 057 String id = action.getId(); 058 if (log.isDebugEnabled()) { 059 if (actions.containsKey(id)) { 060 log.debug("Overriding action: " + action); 061 } else { 062 log.debug("Registering action: " + action); 063 } 064 } 065 // add a default label if not set 066 if (action.getLabel() == null) { 067 action.setLabel(action.getId()); 068 } 069 actions.put(id, action); 070 for (String category : action.getCategories()) { 071 List<String> acts = categories.get(category); 072 if (acts == null) { 073 acts = new ArrayList<String>(); 074 } 075 if (!acts.contains(id)) { 076 acts.add(id); 077 } 078 categories.put(category, acts); 079 } 080 } 081 082 public synchronized Action removeAction(String id) { 083 if (log.isDebugEnabled()) { 084 log.debug("Unregistering action: " + id); 085 } 086 087 Action action = actions.remove(id); 088 if (action != null) { 089 for (String category : action.getCategories()) { 090 List<String> acts = categories.get(category); 091 if (acts != null) { 092 acts.remove(id); 093 } 094 } 095 } 096 return action; 097 } 098 099 public synchronized Collection<Action> getActions() { 100 return Collections.unmodifiableCollection(sortActions(actions.values())); 101 } 102 103 public List<Action> getActions(String category) { 104 List<Action> result = new LinkedList<Action>(); 105 Collection<String> ids; 106 synchronized (this) { 107 ids = categories.get(category); 108 } 109 if (ids != null) { 110 for (String id : ids) { 111 Action action = actions.get(id); 112 if (action != null && action.isEnabled()) { 113 // UI type action compat check 114 Action finalAction = getClonedAction(action); 115 applyCompatibility(category, finalAction); 116 // return only enabled actions 117 result.add(finalAction); 118 } 119 } 120 } 121 result = sortActions(result); 122 return result; 123 } 124 125 protected void applyCompatibility(Action finalAction) { 126 if (finalAction != null && finalAction.getType() == null) { 127 // iterate over all categories to apply compat 128 String[] cats = finalAction.getCategories(); 129 if (cats != null) { 130 for (String cat : cats) { 131 if (applyCompatibility(cat, finalAction)) { 132 break; 133 } 134 } 135 } 136 } 137 } 138 139 protected boolean applyCompatibility(String category, Action finalAction) { 140 if (finalAction != null && finalAction.getType() == null) { 141 for (TypeCompatibility compat : typeCategoryRelations) { 142 for (String compatCategory : compat.getCategories()) { 143 if (StringUtils.equals(compatCategory, category)) { 144 finalAction.setType(compat.getType()); 145 if (applyCustomCompatibility(compat.getType(), finalAction)) { 146 return true; 147 } 148 } 149 } 150 } 151 } 152 return false; 153 } 154 155 /** 156 * Displays specific help messages for migration of actions. 157 * 158 * @since 6.0 159 */ 160 protected boolean applyCustomCompatibility(String compatType, Action action) { 161 // 6.0 BBB: home/admin tab actions migrated to widgets 162 if ("admin_rest_document_link".equals(compatType) || "home_rest_document_link".equals(compatType)) { 163 boolean applied = false; 164 String link = action.getLink(); 165 if (link != null && !link.startsWith("/")) { 166 action.setLink("/" + link); 167 applied = true; 168 } 169 if (applied) { 170 log.warn(String.format("Applied compatibility to action '%s', its configuration " 171 + "should be reviewed: make sure the link references an " + "absolute path", action.getId())); 172 return true; 173 } 174 } 175 return false; 176 } 177 178 public synchronized Action getAction(String id) { 179 Action action = actions.get(id); 180 Action finalAction = getClonedAction(action); 181 applyCompatibility(finalAction); 182 return finalAction; 183 } 184 185 protected Action getClonedAction(Action action) { 186 if (action == null) { 187 return null; 188 } 189 return action.clone(); 190 } 191 192 protected static List<Action> sortActions(Collection<Action> actions) { 193 List<Action> sortedActions = new ArrayList<Action>(); 194 if (actions != null) { 195 sortedActions.addAll(actions); 196 Collections.sort(sortedActions); 197 } 198 return sortedActions; 199 } 200 201 public List<TypeCompatibility> getTypeCategoryRelations() { 202 return typeCategoryRelations; 203 } 204 205 public void setTypeCategoryRelations(List<TypeCompatibility> typeCategoryRelations) { 206 this.typeCategoryRelations = typeCategoryRelations; 207 } 208 209}