View Javadoc
1   /**
2    * This file Copyright (c) 2003-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.cms.beans.config;
35  
36  import info.magnolia.context.MgnlContext;
37  import info.magnolia.context.WebContext;
38  
39  import java.util.ArrayList;
40  import java.util.Iterator;
41  import java.util.List;
42  
43  import org.apache.commons.lang3.StringUtils;
44  
45  /**
46   * Simple VirtualURI mapping that can forward to a different url depending on the request host name. The "mappings" node
47   * contains a list of nodes with "host" and "toURI" properties.
48   * See below for a sample configuration:
49   *
50   * <pre>
51   * [] virtualURIMapping
52   *    [] default
53   *     - class            info.magnolia.cms.beans.config.HostBasedVirtualURIMapping
54   *     - fromURI          /
55   *     - toURI            redirect:/.magnolia/pages/adminCentral.html
56   *       [] mappings
57   *        - [] com
58   *          - host      www.acme.com
59   *          - toURI     forward:/acme/en/index.html
60   *        - [] de
61   *          - host      www.acme.de
62   *          - toURI     forward:/acme/de/index.html
63   * </pre>
64   *
65   * For backwards compatibility The "host" property may still be used, it contains
66   * a list of uri=destination strings.
67   * This technique is deprecated primarily because the properties of a node do not have a deterministic order.
68   * See below for a sample configuration of the deprecated approach using 'hosts' node.:
69   *
70   * <pre>
71   * [] virtualURIMapping
72   *    [] default
73   *     - class            info.magnolia.cms.beans.config.HostBasedVirtualURIMapping
74   *     - fromURI          /
75   *     - toURI            redirect:/.magnolia/pages/adminCentral.html
76   *       [] hosts
77   *        - 1             www.acme.com=forward:/acme/en/index.html
78   *        - 2             www.acme.de=forward:/acme/de/index.html
79   * </pre>
80   *
81   * @deprecated since 5.5.6, host based URI mapping has been relocated to the virtual-uri module (see MAGNOLIA-7016).
82   */
83  @Deprecated
84  public class HostBasedVirtualURIMapping extends DefaultVirtualURIMapping {
85  
86      protected ArrayList<HostURIMapping> hosts;
87  
88      /**
89       *
90       */
91      public HostBasedVirtualURIMapping() {
92          hosts = new ArrayList<HostURIMapping>();
93      }
94  
95      // required by content2bean in order to make addMapping work, do not remove!
96      public List<HostURIMapping> getMappings() {
97          return null;
98      }
99  
100     /**
101      * Adds a mapping (used by content2bean).
102      *
103      * @param mapping object.
104      */
105     public void addMapping(HostURIMapping mapping) {
106         if (mapping.getHost() != null && mapping.getToURI() != null) {
107             synchronized (hosts) {
108                 hosts.add(mapping);
109             }
110         }
111     }
112 
113     // required by content2bean in order to make addHost work, do not remove!
114     // @Deprecated since 4.5.18, content2bean mechanism will recognize getMappings() method to call the addMapping method.
115     @Deprecated
116     public List<String> getHosts() {
117         return null;
118     }
119 
120     /**
121      * @param mapping in the form host=path
122      * @Deprecated since 4.5.18, Use {@link #addMapping(HostURIMapping))} instead.
123      * Adds a host mapping (used by content2bean).
124      */
125     @Deprecated
126     public void addHost(String mapping) {
127         String[] hostToPath = StringUtils.split(mapping, "=");
128         if (hostToPath != null && hostToPath.length == 2) {
129             synchronized (hosts) {
130                 hosts.add(new HostURIMapping(hostToPath[0], hostToPath[1]));
131             }
132         }
133     }
134 
135     @Override
136     public MappingResult mapURI(String uri) {
137 
138         MappingResult result = super.mapURI(uri);
139 
140         if (result != null) {
141             String destination = toURI;
142             String hostMapping = this.tryToMapHost();
143             if (hostMapping != null) {
144                 destination = hostMapping;
145             }
146             result.setToURI(destination);
147             return result;
148         }
149 
150         return null;
151     }
152 
153     /**
154      * Choose the mapping host that matches the request host, with the least number of additional characters.
155      *
156      * @return The URI to map to.
157      */
158     protected String tryToMapHost() {
159         final int NO_MATCHED_MAPPINGS = -1;
160         int bestMatchValue = NO_MATCHED_MAPPINGS;
161         String toURI = null;
162 
163         if (hosts != null && !hosts.isEmpty()) {
164             String requestHost = ((WebContext) MgnlContext.getInstance()).getRequest().getServerName();
165 
166             Iterator<HostURIMapping> hostIt = hosts.iterator();
167 
168             while (hostIt.hasNext()) {
169                 HostURIMapping hk = hostIt.next();
170                 if (hk.isValid() && requestHost.endsWith(hk.getHost())) {
171                     int matchValue = (requestHost.length() - hk.getHost().length());
172                     if (bestMatchValue == NO_MATCHED_MAPPINGS || matchValue < bestMatchValue) {
173                         bestMatchValue = matchValue;
174                         toURI = hk.getToURI();
175                     }
176                 }
177             }
178         }
179         return toURI;
180     }
181 
182     @Override
183     public String toString() {
184         return "[" + super.toString() + "[hosts:" + hosts.toString() + "]]";
185     }
186 
187     @Override
188     public boolean isValid() {
189         if (this.getClass().equals(HostBasedVirtualURIMapping.class)) {
190             return StringUtils.isNotEmpty(getFromURI()) && hosts.stream()
191                     .anyMatch(HostURIMapping::isValid);
192         }
193         return true;
194     }
195 
196     /**
197      * HostURIMapping object to receive "mapping" nodes in configuration.
198      */
199     public static class HostURIMapping {
200 
201         // Empty constructor required for content2bean.
202         public HostURIMapping() {
203         }
204 
205         public HostURIMapping(String host, String toURI) {
206             this.host = host;
207             this.toURI = toURI;
208         }
209 
210         private String host;
211 
212         private String toURI;
213 
214         public String getHost() {
215             return this.host;
216         }
217 
218         public void setHost(String host) {
219             this.host = host;
220         }
221 
222         public String getToURI() {
223             return this.toURI;
224         }
225 
226         public void setToURI(String toURI) {
227             this.toURI = toURI;
228         }
229 
230         public boolean isValid() {
231             return StringUtils.isNotEmpty(host) && StringUtils.isNotEmpty(toURI);
232         }
233 
234         @Override
235         public String toString() {
236             return getHost() + "=" + getToURI();
237 
238         }
239     }
240 
241 }