View Javadoc
1   /**
2    * This file Copyright (c) 2012-2018 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          this.parameter = split.length == 2 ? decodeFragment(split[1]) : "";
96      }
97  
98      private void setAppParams(String appParams) {
99          StringTokenizer tokenizer = new StringTokenizer(appParams, ":");
100         this.appType = decodeFragment((tokenizer.hasMoreTokens()) ? tokenizer.nextToken() : "");
101         this.appName = decodeFragment((tokenizer.hasMoreTokens()) ? tokenizer.nextToken() : "");
102         this.subAppId = decodeFragment((tokenizer.hasMoreTokens()) ? tokenizer.nextToken() : "");
103     }
104 
105     @Override
106     public String getAppType() {
107         return appType;
108     }
109 
110     @Override
111     public String getAppName() {
112         return appName;
113     }
114 
115     @Override
116     public String getSubAppId() {
117         return subAppId;
118     }
119 
120     @Override
121     public String getParameter() {
122         return parameter;
123     }
124 
125     public void setParameter(String parameter) {
126         this.parameter = decodeFragment(parameter);
127     }
128 
129     public void setSubAppId(String subAppId) {
130         this.subAppId = decodeFragment(subAppId);
131     }
132 
133     public void setAppType(String appType) {
134         this.appType = decodeFragment(appType);
135     }
136 
137     public void setAppName(String appName) {
138         this.appName = decodeFragment(appName);
139     }
140 
141     @Override
142     public boolean equals(Object o) {
143         if (this == o) {
144             return true;
145         }
146 
147         if ((o == null) || !(o instanceof  DefaultLocation)) {
148             return false;
149         }
150 
151         DefaultLocation./../../info/magnolia/ui/api/location/DefaultLocation.html#DefaultLocation">DefaultLocation that = (DefaultLocation) o;
152 
153         if (appType != null ? !appType.equals(that.appType) : that.appType != null) {
154             return false;
155         }
156         if (appName != null ? !appName.equals(that.appName) : that.appName != null) {
157             return false;
158         }
159         if (subAppId != null ? !subAppId.equals(that.subAppId) : that.subAppId != null) {
160             return false;
161         }
162         if (parameter != null ? !parameter.equals(that.parameter) : that.parameter != null) {
163             return false;
164         }
165 
166         return true;
167     }
168 
169     @Override
170     public int hashCode() {
171         int result = appType != null ? appType.hashCode() : 0;
172         result = 31 * result + (appName != null ? appName.hashCode() : 0);
173         result = 31 * result + (subAppId != null ? subAppId.hashCode() : 0);
174         result = 31 * result + (parameter != null ? parameter.hashCode() : 0);
175         return result;
176     }
177 
178     @Override
179     public String toString() {
180         StringBuilder sb = new StringBuilder();
181         if (appType != null && appType.length() != 0) {
182             sb.append(appType);
183             if (appName != null && appName.length() != 0) {
184                 sb.append(":").append(appName);
185             }
186             if (subAppId != null && subAppId.length() != 0) {
187                 sb.append(":").append(subAppId);
188             }
189             if (parameter != null && parameter.length() != 0) {
190                 sb.append(";").append(parameter);
191             }
192         }
193         return sb.toString();
194     }
195 
196     public static String extractAppType(String fragment) {
197         int i = fragment.indexOf(':');
198         return i != -1 ? fragment.substring(0, i) : fragment;
199     }
200 
201     public static String extractAppName(String fragment) {
202         fragment = removeParameter(fragment);
203         int i = fragment.indexOf(':');
204         if (i == -1) {
205             return "";
206         }
207         int j = fragment.indexOf(':', i + 1);
208         return j != -1 ? fragment.substring(i + 1, j) : fragment.substring(i + 1);
209     }
210 
211     public static String extractSubAppId(String fragment) {
212         fragment = removeParameter(fragment);
213 
214         int i = fragment.indexOf(':');
215         if (i == -1) {
216             return "";
217         }
218         int j = fragment.indexOf(':', i + 1);
219         if (j == -1) {
220             return "";
221         }
222         return fragment.substring(j + 1);
223     }
224 
225     public static String extractParameter(String fragment) {
226         int i = fragment.indexOf(';');
227         if (i == -1) {
228             return "";
229         }
230         return fragment.substring(i + 1);
231     }
232 
233     private static String removeParameter(String fragment) {
234         int i = fragment.indexOf(';');
235         return i != -1 ? fragment.substring(0, i) : fragment;
236     }
237 
238     /**
239      * Decodes <code>application/x-www-form-urlencoded</code> fragment string using a specified encoding scheme if necessary.
240      */
241     public static String decodeFragment(String fragment, String encoding) {
242         if (fragment == null) {
243             return fragment;
244         }
245 
246         if (fragment.indexOf('%') > -1) {
247             try {
248                 fragment = URLDecoder.decode(fragment, encoding);
249             } catch (UnsupportedEncodingException e) {
250                 log.error("Error decoding fragment '" + fragment + "' with encoding '" + encoding + "'", e);
251             }
252         }
253 
254         return fragment;
255     }
256 
257     /**
258      * Decodes a fragment using the character encoding from the {@link info.magnolia.cms.core.AggregationState}.
259      */
260     public static String decodeFragment(String fragment) {
261         return decodeFragment(fragment, MgnlContext.getAggregationState().getCharacterEncoding());
262     }
263 
264     protected String escapeSpecialCharacters(String toEscape) {
265         return StringUtils.replaceEach(toEscape, SPECIAL_CHARACTERS, SPECIAL_CHARACTERS_REPLACEMENT);
266     }
267 
268     protected String unescapeSpecialCharacters(String toUnescape) {
269         return StringUtils.replaceEach(toUnescape, SPECIAL_CHARACTERS_REPLACEMENT, SPECIAL_CHARACTERS);
270     }
271 
272 }