View Javadoc

1   /**
2    * This file Copyright (c) 2010-2011 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.commands;
35  
36  
37  import info.magnolia.jcr.node2bean.Node2BeanException;
38  import info.magnolia.jcr.node2bean.PropertyTypeDescriptor;
39  import info.magnolia.jcr.node2bean.TransformationState;
40  import info.magnolia.jcr.node2bean.TypeDescriptor;
41  import info.magnolia.jcr.node2bean.TypeMapping;
42  import info.magnolia.jcr.node2bean.impl.Node2BeanTransformerImpl;
43  import info.magnolia.objectfactory.Classes;
44  import info.magnolia.objectfactory.ComponentProvider;
45  
46  import java.util.Iterator;
47  import java.util.Map;
48  
49  import javax.jcr.Node;
50  import javax.jcr.RepositoryException;
51  
52  import org.apache.commons.chain.Catalog;
53  import org.apache.commons.chain.Chain;
54  import org.apache.commons.chain.Command;
55  import org.apache.commons.chain.impl.ChainBase;
56  import org.apache.commons.lang.StringUtils;
57  
58  /**
59  * Command to transform old "impl" reference to implementing class to new "class" node data name for references.
60  * @author gjoseph
61  * @version $Revision: $ ($Author: $)
62  */
63  public class CommandTransformer extends Node2BeanTransformerImpl {
64      private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CommandTransformer.class);
65  
66      private static final String DEPRECATED_CATALOG_NAME_NODE_DATA = "catalogName";
67  
68      private static final String DEPRECATED_IMPL_NODE_DATA = "impl";
69  
70      @Override
71      protected TypeDescriptor onResolveType(TypeMapping typeMapping, TransformationState state, TypeDescriptor resolvedType, ComponentProvider componentProvider) {
72          if(resolvedType != null){
73              return resolvedType;
74          }
75          Class klass = null;
76          // default class to use
77          if(state.getLevel() == 1){
78              klass = MgnlCatalog.class;
79          }
80          else{
81              Node node = state.getCurrentNode();
82              try {
83                  if(node.hasProperty(DEPRECATED_IMPL_NODE_DATA)){
84                      log.warn("Rename  '" + DEPRECATED_IMPL_NODE_DATA + "' to 'class' [" + node + "]!");
85                      try {
86                          final String className = node.getProperty(DEPRECATED_IMPL_NODE_DATA).getString();
87                          klass = Classes.getClassFactory().forName(className);
88                      }
89                      catch (ClassNotFoundException e) {
90                          klass = DelegateCommand.class;
91                      }
92                  }
93                  else{
94                      // In case we are not yet building a concreate command we are creating a chain.
95                      // Otherwise we are building command properties
96                      boolean buildingCommand = false;
97                      for (int i = 0; i < state.getLevel() -1; i++) {
98                          TypeDescriptor td = state.peekType(i);
99                          if(isCommandClass(td.getType()) && !isChainClass(td.getType())){
100                             buildingCommand = true;
101                         }
102                     }
103                     if(!buildingCommand){
104                         klass = ChainBase.class;
105                     }
106                 }
107             }
108             catch (RepositoryException e) {
109                 log.error("Can't check " + DEPRECATED_IMPL_NODE_DATA + " nodedata [" + node + "]", e);
110             }
111         }
112         if(klass != null){
113             return typeMapping.getTypeDescriptor(klass);
114         }
115         return resolvedType;
116     }
117 
118     @Override
119     public void initBean(TransformationState state, Map values) throws Node2BeanException {
120         // we add the commands here (reflection does not work)
121         if(state.getCurrentBean() instanceof Catalog){
122             Catalog catalog = (Catalog) state.getCurrentBean();
123             for (Iterator iter = values.keySet().iterator(); iter.hasNext();) {
124                 String name = (String) iter.next();
125                 if(values.get(name) instanceof Command){
126                     Command command = (Command) values.get(name);
127                     if(!(command instanceof MgnlCommand) || ((MgnlCommand)command).isEnabled()){
128                         catalog.addCommand(name, command);
129                     }
130                 }
131             }
132         }
133 
134         // support chains
135         if(state.getCurrentBean() instanceof Chain){
136             Chain chain = (Chain) state.getCurrentBean();
137             for (Iterator iter = values.values().iterator(); iter.hasNext();) {
138                 Object value = iter.next();
139                 if (value instanceof Command) {
140                     Command command = (Command) value;
141                     if(!(command instanceof MgnlCommand) || ((MgnlCommand)command).isEnabled()){
142                         chain.addCommand(command);
143                     }
144                 }
145             }
146         }
147 
148         // support old way (using impl) of configuring delegate commands
149         if(state.getCurrentBean() instanceof DelegateCommand){
150             DelegateCommand delegateCommand = (DelegateCommand) state.getCurrentBean();
151             if(StringUtils.isEmpty(delegateCommand.getCommandName())){
152                 log.warn("You should define the commandName property on [{}]", state.getCurrentNode());
153                 delegateCommand.setCommandName((String) values.get(DEPRECATED_IMPL_NODE_DATA));
154             }
155         }
156         super.initBean(state, values);
157     }
158 
159     @Override
160     public void setProperty(TypeMapping typeMapping, TransformationState state, PropertyTypeDescriptor descriptor, Map values) throws RepositoryException {
161         Object bean = state.getCurrentBean();
162         if(bean instanceof MgnlCatalog){
163             MgnlCatalog catalog = (MgnlCatalog) bean;
164             if(values.containsKey(DEPRECATED_CATALOG_NAME_NODE_DATA)){
165                 log.warn("Rename the 'catalogName' nodedata to 'name' [" + state.getCurrentNode() + "]");
166                 catalog.setName((String)values.get(DEPRECATED_CATALOG_NAME_NODE_DATA));
167             }
168 
169             if (!values.containsKey("name") && state.getCurrentNode().getName().equals("commands")) {
170                 try {
171                     catalog.setName(state.getCurrentNode().getParent().getName());
172                 }
173                 catch (RepositoryException e) {
174                     log.error("Can't resolve catalog name by using parent node [" + state.getCurrentNode() + "]", e);
175                 }
176             }
177         }
178 
179         super.setProperty(typeMapping, state, descriptor, values);
180     }
181 
182     protected boolean isCommandClass(Class<?> type) {
183         return Command.class.isAssignableFrom(type);
184     }
185 
186     protected boolean isChainClass(Class<?> type) {
187         return Chain.class.isAssignableFrom(type);
188     }
189 }