1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.commands;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.util.DeprecationUtil;
38 import info.magnolia.cms.util.ModuleConfigurationObservingManager;
39 import info.magnolia.commands.chain.Catalog;
40 import info.magnolia.commands.chain.Command;
41 import info.magnolia.commands.chain.Context;
42 import info.magnolia.context.SimpleContext;
43 import info.magnolia.event.EventBus;
44 import info.magnolia.event.SystemEventBus;
45 import info.magnolia.jcr.node2bean.Node2BeanException;
46 import info.magnolia.jcr.node2bean.Node2BeanProcessor;
47 import info.magnolia.jcr.util.NodeTypes;
48 import info.magnolia.jcr.util.NodeUtil;
49 import info.magnolia.module.ModuleRegistry;
50 import info.magnolia.module.ModulesStartedEvent;
51 import info.magnolia.objectfactory.Components;
52
53 import java.util.HashMap;
54 import java.util.Iterator;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.concurrent.atomic.AtomicReference;
58
59 import javax.inject.Inject;
60 import javax.inject.Named;
61 import javax.inject.Singleton;
62 import javax.jcr.Node;
63 import javax.jcr.RepositoryException;
64
65 import org.apache.commons.lang3.StringUtils;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69
70
71
72
73
74
75
76
77 @Singleton
78 public class CommandsManager extends ModuleConfigurationObservingManager {
79
80 private static final Logger log = LoggerFactory.getLogger(CommandsManager.class);
81
82 public static final String DEFAULT_CATALOG = "default";
83
84 public static final String COMMAND_DELIM = "-";
85
86 private final CommandTransformer commandTransformer;
87
88 private final Node2BeanProcessor nodeToBean;
89
90
91
92
93
94 private final AtomicReference<Map<String, MgnlCatalog>> catalogs = new AtomicReference<Map<String, MgnlCatalog>>(new HashMap<String, MgnlCatalog>());
95
96 @Inject
97 public CommandsManager(ModuleRegistry moduleRegistry, Node2BeanProcessor nodeToBean, @Named(SystemEventBus.NAME) EventBus systemEventBus) {
98 super("commands", moduleRegistry);
99 this.nodeToBean = nodeToBean;
100 this.commandTransformer = new CommandTransformer();
101 systemEventBus.addHandler(ModulesStartedEvent.class, new ModulesStartedEvent.Handler() {
102 @Override
103 public void onModuleStartupCompleted(ModulesStartedEvent event) {
104 CommandsManager.this.start();
105 }
106 });
107 }
108
109
110
111
112 public CommandsManager(Node2BeanProcessor nodeToBean) {
113 this(Components.getComponent(ModuleRegistry.class), nodeToBean, Components.getComponentWithAnnotation(EventBus.class, Components.named(SystemEventBus.NAME)));
114 }
115
116 @Override
117 protected void reload(List<Node> nodes) throws RepositoryException {
118 Map<String, MgnlCatalog> foundCatalogs = new HashMap<>();
119 for (Node node : nodes) {
120 registerCatalogs(node, foundCatalogs);
121 }
122 this.catalogs.set(foundCatalogs);
123 }
124
125 protected void registerCatalogs(Node node, Map<String, MgnlCatalog> catalogs) throws RepositoryException {
126
127 Iterator<Node> children = NodeUtil.getNodes(node, NodeTypes.Content.NAME).iterator();
128 if (!children.hasNext()) {
129 registerCatalog(node, catalogs);
130 } else {
131 while (children.hasNext()) {
132 registerCatalogs(children.next(), catalogs);
133 }
134 }
135 }
136
137 protected void registerCatalog(Node node, Map<String, MgnlCatalog> catalogs) {
138 try {
139 log.debug("Registering commands at {}...", node.getPath());
140 MgnlCatalog catalog = (MgnlCatalog) nodeToBean.toBean(node, true, commandTransformer, Components.getComponentProvider());
141 MgnlCatalog current = catalogs.get(catalog.getName());
142 if (current == null) {
143 catalogs.put(catalog.getName(), catalog);
144 log.info("Catalog [{}] registered: {}", catalog.getName(), catalog);
145 } else {
146 for (String commandName : catalog.getNames()) {
147 Command command = current.getCommand(commandName);
148 if (command != null) {
149 log.warn(String.format("Command [%s] found at [%s] already exists in the catalog [%s], skipping...", commandName, node.getPath(), current.getName()));
150 } else {
151 log.info("Adding new command [{}] to already registered catalog [{}]...", commandName, current.getName());
152 current.addCommand(commandName, catalog.getCommand(commandName));
153 }
154 }
155 }
156 } catch (RepositoryException e) {
157 log.error("Can't read catalog [{}]", node, e);
158 } catch (Node2BeanException e) {
159 log.error("Can't create catalog [{}]", node, e);
160 }
161 }
162
163
164
165
166
167
168
169
170 public Command getCommand(String catalogName, String commandName) {
171
172 MgnlCatalog catalog = catalogs.get().get(StringUtils.isNotEmpty(catalogName) ? catalogName : DEFAULT_CATALOG);
173 if (catalog != null) {
174 Command command = catalog.getCommand(commandName);
175 if (command != null) {
176 try {
177 return command.clone();
178 } catch (CloneNotSupportedException e) {
179 log.warn("Cannot create clone of command [{}] from catalog [{}], because command doesn't support the Cloneable interface", commandName, catalogName);
180 }
181 }
182 }
183
184 return null;
185 }
186
187
188
189
190 public Command getCommand(String commandName) {
191 String catalogName = DEFAULT_CATALOG;
192 if (StringUtils.contains(commandName, COMMAND_DELIM)) {
193 catalogName = StringUtils.substringBefore(commandName, COMMAND_DELIM);
194 commandName = StringUtils.substringAfter(commandName, COMMAND_DELIM);
195 }
196
197 Command command = getCommand(catalogName, commandName);
198 if (command == null) {
199 command = getCommand(DEFAULT_CATALOG, commandName);
200 }
201 return command;
202 }
203
204
205
206
207
208 @Deprecated
209 public static CommandsManager getInstance() {
210 return Components.getComponent(CommandsManager.class);
211 }
212
213
214
215
216
217
218 public boolean executeCommand(final String catalogName, final String commandName, final Map<String, Object> params) throws Exception {
219 final Command command = getCommand(catalogName, commandName);
220 if (command == null) {
221 throw new Exception(String.format("Command [%s] could not be found in catalog [%s]", commandName, catalogName));
222 }
223 log.debug("Executing command [{}] from catalog [{}] and params [{}]...", commandName, catalogName, params);
224 return executeCommand(command, params);
225 }
226
227
228
229
230
231
232
233 public boolean executeCommand(final String commandName, final Map<String, Object> params) throws Exception {
234 return executeCommand(DEFAULT_CATALOG, commandName, params);
235 }
236
237
238
239
240
241
242
243 public boolean executeCommand(final Command command, final Map<String, Object> params) throws Exception {
244 return executeCommand(command, params, new SimpleContext());
245 }
246
247
248
249
250
251
252 public boolean executeCommand(final Command command, final Map<String, Object> params, Context context) throws Exception {
253 if (params != null) {
254 context.putAll(params);
255 }
256 return command.execute(context);
257 }
258
259 Catalog getCatalogByName(String name) {
260 return catalogs.get().get(name);
261 }
262
263
264
265
266 @Deprecated
267 protected void onRegister(Content node) {
268 this.register(node);
269 }
270
271
272
273
274 @Deprecated
275 public synchronized void register(Content content) {
276 DeprecationUtil.isDeprecated("Use reload(java.util.List) instead");
277 try {
278 List<Node> observedNodes = getObservedNodes();
279 observedNodes.add(content.getJCRNode());
280 reload(observedNodes);
281 } catch (RepositoryException e) {
282 log.error(e.getMessage(), e);
283 }
284 }
285
286
287
288
289 @Deprecated
290 protected void registerCatalog(Content node) {
291 this.register(node);
292 }
293
294
295
296
297 @Deprecated
298 @Override
299 public synchronized void reload() {
300 DeprecationUtil.isDeprecated("Use reload() instead");
301 super.reload();
302 }
303
304
305
306
307 @Deprecated
308 public void clear() {
309 DeprecationUtil.isDeprecated("Use onClear() instead.");
310 try {
311 this.onClear();
312 } catch (RepositoryException e) {
313 log.error(e.getMessage(), e);
314 }
315 }
316 }