View Javadoc

1   /**
2    * This file Copyright (c) 2003-2010 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.cms.taglibs.util;
35  
36  import info.magnolia.cms.core.HierarchyManager;
37  import info.magnolia.cms.beans.config.ContentRepository;
38  import info.magnolia.cms.beans.runtime.FileProperties;
39  import info.magnolia.cms.core.Content;
40  import info.magnolia.cms.core.ItemType;
41  import info.magnolia.cms.core.NodeData;
42  import info.magnolia.cms.taglibs.Resource;
43  import info.magnolia.context.MgnlContext;
44  import org.apache.commons.io.IOUtils;
45  import org.apache.commons.lang.StringUtils;
46  import org.devlib.schmidt.imageinfo.ImageInfo;
47  import org.slf4j.Logger;
48  import org.slf4j.LoggerFactory;
49  
50  import javax.jcr.AccessDeniedException;
51  import javax.jcr.PathNotFoundException;
52  import javax.jcr.PropertyType;
53  import javax.jcr.RepositoryException;
54  import javax.servlet.http.HttpServletRequest;
55  import javax.servlet.jsp.PageContext;
56  import javax.servlet.jsp.tagext.SimpleTagSupport;
57  import java.awt.Color;
58  import java.io.File;
59  import java.io.FileInputStream;
60  import java.io.FileNotFoundException;
61  import java.io.IOException;
62  import java.io.InputStream;
63  import java.text.CharacterIterator;
64  import java.text.StringCharacterIterator;
65  import java.util.Calendar;
66  import java.util.GregorianCalendar;
67  import java.util.TimeZone;
68  
69  
70  /**
71   * @author Fabrizio Giustina
72   */
73  public abstract class BaseImageTag extends SimpleTagSupport {
74  
75      /**
76       * The value of the extension nodeData in the properties node.
77       */
78      protected static final String PROPERTIES_EXTENSION_VALUE = "PNG";
79  
80      /**
81       * The valye of the contentType nodeData in the properties node.
82       */
83      protected static final String PROPERTIES_CONTENTTYPE_VALUE = "image/png";
84  
85      /**
86       * Logger.
87       */
88      private static Logger log = LoggerFactory.getLogger(BaseImageTag.class);
89  
90      /**
91       * Attribute: The node where the images are to be saved. If null, the default will be the current active page.
92       */
93      protected String parentContentNodeName;
94  
95      /**
96       * Attribute: The name of the new content node to create. The images will be saved under this node. If this name
97       * starts with a '/', it will be assumed to be a node handle that is relative to the rooot of the website.
98       * Otherwise, it is assumed to be a path relative to the currentActivePage.
99       */
100     protected String imageContentNodeName;
101 
102     /**
103      * Setter for the <code>imageContentNodeName</code> tag attribute.
104      * @param imageContentNodeName
105      */
106     public void setImageContentNodeName(String imageContentNodeName) {
107         this.imageContentNodeName = imageContentNodeName;
108     }
109 
110     /**
111      * Setter for the <code>parentContentNodeName</code> tag attribute.
112      * @param parentContentNodeName
113      */
114     public void setParentContentNodeName(String parentContentNodeName) {
115         this.parentContentNodeName = parentContentNodeName;
116     }
117 
118     protected abstract String getFilename();
119 
120     protected HttpServletRequest getRequest() {
121         return (HttpServletRequest) ((PageContext) this.getJspContext()).getRequest();
122     }
123 
124     /**
125      * @throws PathNotFoundException
126      * @throws RepositoryException
127      * @throws AccessDeniedException
128      */
129     protected Content getImageContentNode() throws PathNotFoundException, RepositoryException,
130         info.magnolia.cms.security.AccessDeniedException {
131 
132         Content imageContentNode;
133         Content currentActivePage = Resource.getCurrentActivePage();
134         Content paragraph = Resource.getLocalContentNode();
135         Content parentContentNode = null;
136         // set the image parent node
137         if (StringUtils.isEmpty(this.parentContentNodeName)) {
138             parentContentNode = paragraph != null ? paragraph : currentActivePage;
139         }
140         else {
141 
142             HierarchyManager hm = MgnlContext.getHierarchyManager(ContentRepository.WEBSITE);
143             // if this name starts with a '/', then assume it is a node handle
144             // otherwise assume that its is a path relative to the current active page
145             if (this.parentContentNodeName.startsWith("/")) {
146                 parentContentNode = hm.getContent(this.parentContentNodeName);
147             }
148             else {
149                 parentContentNode = hm.getContent(currentActivePage.getHandle() + "/" + this.parentContentNodeName);
150             }
151         }
152         // set the node under which the images will be saved
153         imageContentNode = null;
154         if (StringUtils.isEmpty(this.imageContentNodeName)) {
155             imageContentNode = parentContentNode;
156         }
157         else if (parentContentNode.hasContent(this.imageContentNodeName)) {
158             imageContentNode = parentContentNode.getContent(this.imageContentNodeName);
159         }
160         else {
161             imageContentNode = parentContentNode.createContent(this.imageContentNodeName, ItemType.CONTENTNODE);
162             parentContentNode.save();
163         }
164         return imageContentNode;
165     }
166 
167     /**
168      * Replace any special characters that are not letters or numbers with a replacement string. The two exceptions are
169      * '-' and '_', which are allowed.
170      */
171     public String convertToSimpleString(String string) {
172 
173         final StringBuffer result = new StringBuffer();
174 
175         final StringCharacterIterator iterator = new StringCharacterIterator(string);
176         char character = iterator.current();
177         while (character != CharacterIterator.DONE) {
178             int charType = Character.getType(character);
179             if (charType == Character.SPACE_SEPARATOR) {
180                 result.append("-");
181             }
182             else if ((charType != Character.UPPERCASE_LETTER)
183                 && (charType != Character.LOWERCASE_LETTER)
184                 && (charType != Character.DECIMAL_DIGIT_NUMBER)
185                 && (charType != Character.CONNECTOR_PUNCTUATION)
186                 && (charType != Character.DASH_PUNCTUATION)) {
187                 result.append("u" + (int) character);
188 
189             }
190             else {
191                 // the char is not a special one
192                 // add it to the result as is
193                 result.append(character);
194             }
195             character = iterator.next();
196         }
197         return result.toString();
198     }
199 
200     /**
201      * Converts HEX color to RGB color.
202      * @param hex HEX value
203      */
204     public int[] convertHexToRGB(String hex) {
205         hex.trim();
206         if (hex.startsWith("#")) {
207             hex = hex.substring(1);
208         }
209         if (hex.length() == 3) {
210             // allow three digit codes like for css
211             hex = String.valueOf(hex.charAt(0))
212                 + String.valueOf(hex.charAt(0))
213                 + String.valueOf(hex.charAt(1))
214                 + String.valueOf(hex.charAt(1))
215                 + String.valueOf(hex.charAt(2))
216                 + String.valueOf(hex.charAt(2));
217         }
218 
219         int[] rgb = new int[3];
220         try {
221             // Convert rrggbb string to hex ints
222             rgb[0] = Integer.parseInt(hex.substring(0, 2), 16);
223             rgb[1] = Integer.parseInt(hex.substring(2, 4), 16);
224             rgb[2] = Integer.parseInt(hex.substring(4), 16);
225         }
226         catch (NumberFormatException e) {
227             log.error("NumberFormatException occured during text-to-image conversion: "
228                 + "Attempting to convert Hex ["
229                 + hex
230                 + "] color to RGB color: "
231                 + e.getMessage(), e);
232             rgb = new int[]{255, 0, 0}; // red
233         }
234         return rgb;
235     }
236 
237     public Color convertHexToColor(String hex) {
238         int[] rgb = convertHexToRGB(hex);
239         Color color = new Color(rgb[0], rgb[1], rgb[2]);
240         return color;
241     }
242 
243     /**
244      * Create a new imageNode with the image in it. The node is saved under a node that groups all image nodes, whose
245      * name is set to the value of the attribute imageContentNodeName. The name of the node will be set to a name that
246      * is unique for the image. The property that stores the image will be set to the value of
247      * PROPERTIES_FILENAME_VALUE. A sub-node is also created that stores the image properties.
248      * @param subString The text.
249      * @param textImageNode The node that will contain the text images.
250      */
251     protected void createImageNode(File imageFile, Content imageNode) throws PathNotFoundException,
252         AccessDeniedException, RepositoryException, FileNotFoundException, IOException {
253 
254         // Create and save the image data
255         NodeData data;
256         data = imageNode.getNodeData(getFilename());
257 
258         if (!data.isExist()) {
259             data = imageNode.createNodeData(getFilename(), PropertyType.BINARY);
260         }
261 
262         InputStream iis = new FileInputStream(imageFile);
263         data.setValue(iis);
264         IOUtils.closeQuietly(iis);
265 
266         data.setAttribute(FileProperties.PROPERTY_FILENAME, getFilename());
267 
268         data.setAttribute(FileProperties.PROPERTY_CONTENTTYPE, PROPERTIES_CONTENTTYPE_VALUE);
269 
270         Calendar value = new GregorianCalendar(TimeZone.getDefault());
271         data.setAttribute(FileProperties.PROPERTY_LASTMODIFIED, value);
272 
273         data.setAttribute(FileProperties.PROPERTY_SIZE, Long.toString(imageFile.length()));
274 
275         data.setAttribute(FileProperties.PROPERTY_EXTENSION, PROPERTIES_EXTENSION_VALUE);
276 
277         InputStream raf = null;
278         try {
279             ImageInfo ii = new ImageInfo();
280             raf = new FileInputStream(imageFile);
281             ii.setInput(raf);
282             if (ii.check()) {
283                 data.setAttribute(FileProperties.PROPERTY_WIDTH, Long.toString(ii.getWidth()));
284                 data.setAttribute(FileProperties.PROPERTY_HEIGHT, Long.toString(ii.getHeight()));
285 
286             }
287         }
288         catch (FileNotFoundException e) {
289             log.error("FileNotFoundException caught when parsing {}, image data will not be available", imageFile
290                 .getAbsolutePath());
291         }
292         finally {
293             IOUtils.closeQuietly(raf);
294         }
295 
296         // delete the temporary file
297         imageFile.delete();
298 
299         // update modification date and save the new image node
300         imageNode.getMetaData().setModificationDate();        
301         imageNode.getParent().save();
302     }
303 }