View Javadoc
1   /**
2    * This file Copyright (c) 2012-2017 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.ui.api.location;
35  
36  import info.magnolia.context.MgnlContext;
37  
38  import java.io.UnsupportedEncodingException;
39  import java.net.URLDecoder;
40  import java.util.StringTokenizer;
41  
42  import org.apache.commons.lang3.StringUtils;
43  import org.slf4j.Logger;
44  import org.slf4j.LoggerFactory;
45  
46  /**
47   * Default location implementation. Follows the pattern: {@code appType:appName:subAppId;some/parameter}.
48   */
49  public class DefaultLocation implements Location {
50  
51      private static final String[] SPECIAL_CHARACTERS = new String[]{";", ":"};
52      private static final String[] SPECIAL_CHARACTERS_REPLACEMENT = new String[]{"[semi]", "[colon]"};
53  
54      private static Logger log = LoggerFactory.getLogger(DefaultLocation.class);
55  
56      private String appType;
57  
58      private String appName;
59  
60      private String subAppId;
61  
62      private String parameter;
63  
64      public DefaultLocation() {
65      }
66  
67      public DefaultLocation(String appType, String appName) {
68          this(appType, appName, "");
69      }
70  
71      public DefaultLocation(String appType, String appName, String subAppId) {
72          this(appType, appName, subAppId, "");
73      }
74  
75      public DefaultLocation(String appType, String appName, String subAppId, String parameter) {
76          this.appType = decodeFragment(appType);
77          this.appName = decodeFragment(appName);
78          this.subAppId = decodeFragment(subAppId);
79          this.parameter = decodeFragment(parameter);
80      }
81  
82      /**
83       * @throws IllegalArgumentException if the passed fragment is null or empty.
84       */
85      public DefaultLocation(String fragment) {
86          if (StringUtils.isBlank(fragment)) {
87              throw new IllegalArgumentException("Fragment cannot be empty or null");
88          }
89          parseLocation(fragment);
90      }
91  
92      private void parseLocation(String fragment) {
93          String[] split = StringUtils.split(fragment, ";");
94          setAppParams(split[0]);
95          if (split.length == 2) {
96              this.parameter = decodeFragment(split[1]);
97          }
98      }
99  
100     private void setAppParams(String appParams) {
101         StringTokenizer tokenizer = new StringTokenizer(appParams, ":");
102         this.appType = decodeFragment((tokenizer.hasMoreTokens()) ? tokenizer.nextToken() : "");
103         this.appName = decodeFragment((tokenizer.hasMoreTokens()) ? tokenizer.nextToken() : "");
104         this.subAppId = decodeFragment((tokenizer.hasMoreTokens()) ? tokenizer.nextToken() : "");
105     }
106 
107     @Override
108     public String getAppType() {
109         return appType;
110     }
111 
112     @Override
113     public String getAppName() {
114         return appName;
115     }
116 
117     @Override
118     public String getSubAppId() {
119         return subAppId;
120     }
121 
122     @Override
123     public String getParameter() {
124         return parameter;
125     }
126 
127     public void setParameter(String parameter) {
128         this.parameter = decodeFragment(parameter);
129     }
130 
131     public void setSubAppId(String subAppId) {
132         this.subAppId = decodeFragment(subAppId);
133     }
134 
135     public void setAppType(String appType) {
136         this.appType = decodeFragment(appType);
137     }
138 
139     public void setAppName(String appName) {
140         this.appName = decodeFragment(appName);
141     }
142 
143     @Override
144     public boolean equals(Object o) {
145         if (this == o) {
146             return true;
147         }
148 
149         if ((o == null) || !(o instanceof  DefaultLocation)) {
150             return false;
151         }
152 
153         DefaultLocation that = (DefaultLocation) o;
154 
155         if (appType != null ? !appType.equals(that.appType) : that.appType != null) {
156             return false;
157         }
158         if (appName != null ? !appName.equals(that.appName) : that.appName != null) {
159             return false;
160         }
161         if (subAppId != null ? !subAppId.equals(that.subAppId) : that.subAppId != null) {
162             return false;
163         }
164         if (parameter != null ? !parameter.equals(that.parameter) : that.parameter != null) {
165             return false;
166         }
167 
168         return true;
169     }
170 
171     @Override
172     public int hashCode() {
173         int result = appType != null ? appType.hashCode() : 0;
174         result = 31 * result + (appName != null ? appName.hashCode() : 0);
175         result = 31 * result + (subAppId != null ? subAppId.hashCode() : 0);
176         result = 31 * result + (parameter != null ? parameter.hashCode() : 0);
177         return result;
178     }
179 
180     @Override
181     public String toString() {
182         StringBuilder sb = new StringBuilder();
183         if (appType != null && appType.length() != 0) {
184             sb.append(appType);
185             if (appName != null && appName.length() != 0) {
186                 sb.append(":").append(appName);
187             }
188             if (subAppId != null && subAppId.length() != 0) {
189                 sb.append(":").append(subAppId);
190             }
191             if (parameter != null && parameter.length() != 0) {
192                 sb.append(";").append(parameter);
193             }
194         }
195         return sb.toString();
196     }
197 
198     public static String extractAppType(String fragment) {
199         int i = fragment.indexOf(':');
200         return i != -1 ? fragment.substring(0, i) : fragment;
201     }
202 
203     public static String extractAppName(String fragment) {
204         fragment = removeParameter(fragment);
205         int i = fragment.indexOf(':');
206         if (i == -1) {
207             return "";
208         }
209         int j = fragment.indexOf(':', i + 1);
210         return j != -1 ? fragment.substring(i + 1, j) : fragment.substring(i + 1);
211     }
212 
213     public static String extractSubAppId(String fragment) {
214         fragment = removeParameter(fragment);
215 
216         int i = fragment.indexOf(':');
217         if (i == -1) {
218             return "";
219         }
220         int j = fragment.indexOf(':', i + 1);
221         if (j == -1) {
222             return "";
223         }
224         return fragment.substring(j + 1);
225     }
226 
227     public static String extractParameter(String fragment) {
228         int i = fragment.indexOf(';');
229         if (i == -1) {
230             return "";
231         }
232         return fragment.substring(i + 1);
233     }
234 
235     private static String removeParameter(String fragment) {
236         int i = fragment.indexOf(';');
237         return i != -1 ? fragment.substring(0, i) : fragment;
238     }
239 
240     /**
241      * Decodes <code>application/x-www-form-urlencoded</code> fragment string using a specified encoding scheme if necessary.
242      */
243     public static String decodeFragment(String fragment, String encoding) {
244         if (fragment == null) {
245             return fragment;
246         }
247 
248         if (fragment.indexOf('%') > -1) {
249             try {
250                 fragment = URLDecoder.decode(fragment, encoding);
251             } catch (UnsupportedEncodingException e) {
252                 log.error("Error decoding fragment '" + fragment + "' with encoding '" + encoding + "'", e);
253             }
254         }
255 
256         return fragment;
257     }
258 
259     /**
260      * Decodes a fragment using the character encoding from the {@link info.magnolia.cms.core.AggregationState}.
261      */
262     public static String decodeFragment(String fragment) {
263         return decodeFragment(fragment, MgnlContext.getAggregationState().getCharacterEncoding());
264     }
265 
266     protected String escapeSpecialCharacters(String toEscape) {
267         return StringUtils.replaceEach(toEscape, SPECIAL_CHARACTERS, SPECIAL_CHARACTERS_REPLACEMENT);
268     }
269 
270     protected String unescapeSpecialCharacters(String toUnescape) {
271         return StringUtils.replaceEach(toUnescape, SPECIAL_CHARACTERS_REPLACEMENT, SPECIAL_CHARACTERS);
272     }
273 
274 }