View Javadoc
1   /**
2    * This file Copyright (c) 2012-2015 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.dam.app.setup.migration;
35  
36  import info.magnolia.dam.api.ItemKey;
37  import info.magnolia.dam.jcr.DamConstants;
38  import info.magnolia.jcr.util.NodeTypes;
39  import info.magnolia.jcr.util.NodeUtil;
40  import info.magnolia.jcr.util.NodeVisitor;
41  
42  import java.util.ArrayList;
43  import java.util.Arrays;
44  import java.util.List;
45  
46  import javax.jcr.ItemNotFoundException;
47  import javax.jcr.Node;
48  import javax.jcr.Property;
49  import javax.jcr.PropertyIterator;
50  import javax.jcr.RepositoryException;
51  
52  import org.apache.commons.lang.StringUtils;
53  import org.apache.jackrabbit.core.id.NodeId;
54  import org.slf4j.Logger;
55  import org.slf4j.LoggerFactory;
56  
57  /**
58   * This task is responsible for cleaning the content repository.<br>
59   * Iterate the list of contentPathsList, get the related Node, and apply the
60   * visitor to the Node tree.<br>
61   * It use the {@link NodeVisitor} pattern. In order to define your own
62   * NodeVisior, extend this migration task and override the addCustomVisitors()
63   * protected method.<br>
64   * 
65   * <pre>
66   * Implemented visitor:
67   *   <B>CleanUpNodeVisitor</B>
68   * Condition:
69   *   Node must be of type mgnl:content or mgnl:page
70   *    and
71   *   must have one of the following property : image , video , flash , logoImg, printLogoImg --> index.
72   * Action
73   *  If the value of the property is an Identifier
74   *  and Identifier is not linked to a DAM node
75   *  remove it.
76   *    <B>HandleDamLinkNodeVisitor</B>
77   * Condition:
78   *   Node must be of type mgnl:content or mgnl:page
79   *    and
80   *   must have the following property : link --> index.
81   * Action
82   *  If the value of the property is an Identifier
83   *  and Identifier is linked to a DAM node
84   *  Create a composite key.
85   * </pre>
86   **/
87  public class CleanContentForDamMigrationTask extends AbstractCleanContentForDamMigrationTask {
88  
89      private static final Logger log = LoggerFactory.getLogger(CleanContentForDamMigrationTask.class);
90  
91      /**
92       * Default constructor.
93       */
94      public CleanContentForDamMigrationTask(String taskName, String taskDescription, String contentRepository, List<String> contentPathsList) {
95          super(taskName, taskDescription, contentRepository, contentPathsList);
96      }
97  
98      /**
99       * Override in order to add your custom visitors.
100      */
101     @Override
102     protected List<NodeVisitor> addCustomVisitors() {
103         List<NodeVisitor> visitorList = new ArrayList<NodeVisitor>();
104         visitorList.add(createCleanUpNodeVisitor());
105         visitorList.add(createHandleDamLinkNodeVisitor());
106         return visitorList;
107     }
108 
109     /**
110      * Create the node property prefix used in the Clean Up Node visitor.
111      * Used to filter Node properties and return only the properties part of the prefix list.
112      * Current prefix defined:
113      * image , video , flash , logoImg, printLogoImg, teaserImg.
114      */
115     protected String[] createCleanUpVisitorPrefixTable() {
116         return new String[] { "image", "video", "flash", "logoImg", "printLogoImg", "teaserImg", "image_*", "video_*", "flash_*", "logoImg_*", "printLogoImg_*", "teaserImg_*" };
117     }
118 
119     /**
120      * prefix list : image , video , flash , logoImg, printLogoImg, teaserImg.
121      * Condition:
122      * node type = mgnl:component or mgnl:page
123      * Action:
124      * remove properties part of the prefix list found in the Node
125      * if this property is an identifier and not linked to an DAM existing Node.
126      */
127     private NodeVisitor createCleanUpNodeVisitor() {
128         NodeVisitor cleanUpVisitor = new NodeVisitor() {
129             private String[] prefix = createCleanUpVisitorPrefixTable();
130 
131             @Override
132             public void visit(Node node) throws RepositoryException {
133                 if (NodeUtil.isNodeType(node, NodeTypes.Page.NAME) || NodeUtil.isNodeType(node, NodeTypes.Component.NAME)) {
134                     PropertyIterator propertyIterator = node.getProperties(prefix);
135                     while (propertyIterator.hasNext()) {
136                         Property property = propertyIterator.nextProperty();
137                         if (!StringUtils.contains(property.getName(), "_") || DamMigrationUtil.isPropertyNameI18nBased(property.getName())) {
138                             // Take Action
139                             cleanUpVisitorTakeAction(node, property);
140                         }
141                     }
142                 }
143             }
144         };
145         return cleanUpVisitor;
146     }
147 
148     /**
149      * Take action of the node property:
150      * Check if the property value is a valid Identifier.
151      * If it's an Identifier and not related to DAM, remove the property
152      */
153     private void cleanUpVisitorTakeAction(Node node, Property property) throws RepositoryException {
154 
155         try {
156             // In case of it is not an Identifier, this will throw a IllegalArgumentException
157             NodeId.valueOf(ItemKey.from(property.getString()).getAssetId());
158             if (!damNodeExist(ItemKey.from(property.getString()).getAssetId())) {
159                 log.warn("The property {} located under {} with value {} seems not to be related to an Identifier. This property will be removed.'",
160                         Arrays.asList(property.getName(), property.getPath(), property.getString()));
161                 property.remove();
162             }
163         } catch (IllegalArgumentException ie) {
164             log.info("The property {} located under {} with value {} seems not to be related to an Identifier. This property will be keeped.'",
165                     Arrays.asList(property.getName(), property.getPath(), property.getString()));
166         }
167     }
168 
169     /**
170      * Condition:<br>
171      * node type = mgnl:component or mgnl:page and has a property named link <br>
172      * Action:<br>
173      * create a composite id if this property is an identifier and linked to an
174      * DAM existing Node.
175      */
176     private NodeVisitor createHandleDamLinkNodeVisitor() {
177         NodeVisitor cleanUpVisitor = new NodeVisitor() {
178             private String[] prefix = new String[] { "link", "link_*" };
179 
180             @Override
181             public void visit(Node node) throws RepositoryException {
182                 if (NodeUtil.isNodeType(node, NodeTypes.Page.NAME) || NodeUtil.isNodeType(node, NodeTypes.Component.NAME)) {
183                     PropertyIterator propertyIterator = node.getProperties(prefix);
184                     while (propertyIterator.hasNext()) {
185                         Property property = propertyIterator.nextProperty();
186                         if (!StringUtils.contains(property.getName(), "_") || DamMigrationUtil.isPropertyNameI18nBased(property.getName())) {
187                             // Take Action
188                             handleDamLinkVisitorTakeAction(node, property);
189                         }
190                     }
191                 }
192             }
193         };
194         return cleanUpVisitor;
195     }
196 
197     /**
198      * Take action of the node property:<br>
199      * Check if the property value is a valid Identifier.<br>
200      * If it's an Identifier and related to DAM, create a composite Id <br>
201      */
202     private void handleDamLinkVisitorTakeAction(Node node, Property property) throws RepositoryException {
203 
204         try {
205             String damIdentifier = property.getString();
206             // In case of it is not an Identifier, this will throw a
207             // IllegalArgumentException
208             NodeId.valueOf(damIdentifier);
209             if (damNodeExist(damIdentifier)) {
210                 log.info("The property {} located under {} with value {} is related to an DAM Identifier. This property will be Changed to a Composite ID.'",
211                         Arrays.asList(property.getName(), property.getPath(), damIdentifier));
212                 property.setValue(new ItemKey(DamConstants.DEFAULT_JCR_PROVIDER_ID, damIdentifier).asString());
213             }
214         } catch (IllegalArgumentException ie) {
215             log.debug("The property {} located under {} with value {} seems not to be related to an Identifier. This property will be keeped.'",
216                     Arrays.asList(property.getName(), property.getPath(), property.getString()));
217         }
218     }
219 
220     /**
221      * Utility method.
222      * Check if the identifier exist in the DAM repository.
223      */
224     private boolean damNodeExist(String identifier) {
225         try {
226             damSession.getNodeByIdentifier(identifier);
227             return true;
228         } catch (ItemNotFoundException infe) {
229             log.debug("Following identifier not found in the DAM workspace " + identifier);
230             return false;
231         } catch (RepositoryException re) {
232             log.warn("DamSession.getNodeByIdentifier({}) generated a RepositoryException.", identifier, re);
233             return false;
234         }
235     }
236 }