001 /*
002 Copyright (c) 1996-2012, Damon Hart-Davis
003 All rights reserved.
004
005 Redistribution and use in source and binary forms, with or without
006 modification, are permitted provided that the following conditions are
007 met:
008
009 * Redistributions of source code must retain the above copyright
010 notice, this list of conditions and the following disclaimer.
011
012 * Redistributions in binary form must reproduce the above copyright
013 notice, this list of conditions and the following disclaimer in the
014 documentation and/or other materials provided with the
015 distribution.
016
017 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
018 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
019 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
020 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
021 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
022 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
024 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
025 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
027 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028 */
029
030 package org.hd.d.pg2k.webSvr.virtualHosts;
031
032 import java.util.Arrays;
033 import java.util.Collections;
034 import java.util.HashMap;
035 import java.util.HashSet;
036 import java.util.Iterator;
037 import java.util.List;
038 import java.util.Map;
039 import java.util.Set;
040
041 import org.hd.d.pg2k.svrCore.CoreConsts;
042 import org.hd.d.pg2k.svrCore.HostUtils;
043 import org.hd.d.pg2k.webSvr.util.WebConsts;
044
045 /**
046 * Created by IntelliJ IDEA.
047 * User: Damon Hart-Davis
048 * Date: 27-Jun-2003
049 * Time: 18:08:17
050 */
051
052 /**Contains details of the virtual hosts supported.
053 * This also contains the current canonical list of skin names.
054 */
055 public final class VirtualHosts
056 {
057 /**Skin name for black background, minimalist page style. */
058 public static final String SKIN_BLACK_MINIMAL = "blackMin";
059
060 /**Skin name for basic .mobi compliant site. */
061 public static final String SKIN_MOBI_BASIC = "mobiBasic";
062
063 /**Default virtual host description (ie keyed from main site name) for default livery, etc.
064 * Default livery has normal navigation, advertising, layout, etc.
065 */
066 public static final VirtualHost VIRTUAL_HOST_DEFAULT =
067 new VirtualHost(CoreConsts.MAIN_DATA_HOST, null, null,
068 new String[]{ // Aliases, some deprecated...
069 "data.pg2k.hd.org",
070 // "hd.org", "d.hd.org",
071 });
072
073 /**IPv6-only virtual host description (ie keyed from main site name) for default livery, etc.
074 * Default livery has normal navigation, advertising, layout, etc.
075 */
076 public static final VirtualHost VIRTUAL_HOST_IPv6 =
077 new VirtualHost("ipv6.gallery.hd.org", null, null, null);
078
079 /**IPv6-only virtual host description (ie keyed from main site name) for default livery, etc.
080 * Default livery has normal navigation, advertising, layout, etc.
081 */
082 public static final VirtualHost VIRTUAL_HOST_IPv4 =
083 new VirtualHost("ipv4.gallery.hd.org", null, null, null);
084
085 /**Virtual host description and main name for SmlPx.
086 * This is a basic .mobi-compliant version of the Gallery.
087 */
088 public static final VirtualHost VIRTUAL_HOST_SMLPX =
089 new VirtualHost("smlpx.mobi",
090 WebConsts.VIRTUAL_SITE_CUST_SMLPX_ROOT,
091 SKIN_MOBI_BASIC,
092 null);
093
094 /**Virtual host description and main name for Aloha Earth.
095 * Aloha Earth has a black background and minimalist furniture.
096 */
097 public static final VirtualHost VIRTUAL_HOST_ALOHAEARTH =
098 new VirtualHost("aloha-earth.com",
099 WebConsts.VIRTUAL_SITE_CUST_ALOHAEARTH_ROOT,
100 SKIN_BLACK_MINIMAL,
101 new String[]{ // Deprecated aliases...
102 "aloha-earth.org", "alohaearth.org", "alohaearth.com"
103 });
104
105 /**Virtual host description and main name for LondonPix.
106 * LondonPix has a black background and minimalist furniture.
107 */
108 public static final VirtualHost VIRTUAL_HOST_LONDONPIX =
109 new VirtualHost("londonpix.org.uk",
110 WebConsts.VIRTUAL_SITE_CUST_LONDONPIX_ROOT,
111 SKIN_BLACK_MINIMAL, null);
112
113 /**Virtual host description and main name for ZAPix.
114 * ZAPix has a black background and minimalist furniture.
115 */
116 public static final VirtualHost VIRTUAL_HOST_ZAPIX =
117 new VirtualHost("pix.org.za",
118 WebConsts.VIRTUAL_SITE_CUST_ZAPIX_ROOT,
119 SKIN_BLACK_MINIMAL,
120 new String[]{ // Deprecated aliases.
121 "photo.org.za", "photos.org.za"
122 });
123
124 /**Virtual host description and main name for localhost; primarily for testing.
125 * Usually standard livery, but need not be so.
126 */
127 public static final VirtualHost VIRTUAL_HOST_LOCALHOST =
128 new VirtualHost("localhost", null, null, null);
129
130 /**Virtual host description and main name for localhost as literal IPv4 address; primarily for testing.
131 * Usually standard livery, but need not be so.
132 */
133 public static final VirtualHost VIRTUAL_HOST_127p0p0p1 =
134 new VirtualHost("127.0.0.1", null, null, null);
135
136 /**Virtual host description and main name for localhost as literal IPv6 address; primarily for testing.
137 * Usually standard livery, but need not be so.
138 */
139 public static final VirtualHost VIRTUAL_HOST_cc1 =
140 new VirtualHost("[::1]", null, null, null);
141
142 /**Public (immutable) List of canonical "main" VirtualHost descriptions.
143 * In principle all host names or site URIs should map to one of these,
144 * and we may even force redirects and so on so that search engines
145 * and users learn and use these canonical versions.
146 * <p>
147 * This is not intended for fast lookup,
148 * and nothing is implied by the order of entries.
149 * <p>
150 * This should help:
151 * <ul>
152 * <li>Reduce complexity of PG2K management, eg in deployment descriptors.
153 * <li>Reduce redundant Web spider activity to deprecated host names.
154 * <li>Improve load balancing by making better use of "core" aliases.
155 * </ul>
156 */
157 public static final List<VirtualHost> canonicalVirtualHosts =
158 Collections.unmodifiableList(Arrays.asList(new VirtualHost[]{
159 VIRTUAL_HOST_DEFAULT,
160 VIRTUAL_HOST_LONDONPIX,
161 VIRTUAL_HOST_ZAPIX,
162 VIRTUAL_HOST_SMLPX,
163 VIRTUAL_HOST_ALOHAEARTH,
164 VIRTUAL_HOST_IPv4, VIRTUAL_HOST_IPv6,
165 VIRTUAL_HOST_LOCALHOST, VIRTUAL_HOST_127p0p0p1, VIRTUAL_HOST_cc1
166 }));
167
168 /**Public (immutable) Map from String normalised host name to VirtualHost.
169 * This is built from the main and alias host names.
170 * <p>
171 * For the moment this is hard-wired in;
172 * it may become loadable in GenProps in future.
173 */
174 public static final Map<String,VirtualHost> hostDetails;
175 /**Initialise hostDetails. */
176 static
177 {
178 // Create the underlying host map as a HashMap for speed.
179 final Map<String,VirtualHost> hm = new HashMap<String, VirtualHost>(1 + 3 * canonicalVirtualHosts.size());
180
181 // Make entries for all the canonical and alias names...
182 for(final Iterator<VirtualHost> it = canonicalVirtualHosts.iterator(); it.hasNext(); )
183 {
184 final VirtualHost vh = it.next();
185 if(hm.put(vh.normalisedName, vh) != null)
186 { System.err.println("WARNING: duplicate virtual host name: " + vh.normalisedName); }
187 for(final Iterator<String> it2 = vh.normalisedAliasNames.iterator(); it2.hasNext(); )
188 {
189 final String an = it2.next();
190 if(hm.put(an, vh) != null)
191 { System.err.println("WARNING: duplicate virtual host name: " + an); }
192 }
193 }
194
195 hostDetails = Collections.unmodifiableMap(hm);
196 }
197
198 /**Lookup VirtualHost details by hostname and request URL; null if no match found.
199 * The hostname supplied is normalised before lookup.
200 * <p>
201 * Before a lookup by hostname is attempted,
202 * a match is attempted on the request URI
203 * iff the URI starts with the normal prefix for virtual sites.
204 * If a virtual host root is a prefix of the request URI
205 * then we force usage of the the virtual host livery.
206 *
207 * @param serverHostname the host name with which the page was fetched,
208 * as from request.getServerName()
209 * @param requestURI the within-host URI as from request.getRequestURI(),
210 * or null for a faster lookup just by normalised name
211 */
212 public static VirtualHost getVirtualHostDetails(final String serverHostname,
213 final String requestURI)
214 {
215 // Try lookup on the URI first iff it looks like a virtual site.
216 if((requestURI != null) &&
217 (requestURI.startsWith(WebConsts.VIRTUAL_SITES_ROOT)))
218 {
219 // This is potentially a little slow,
220 // and does not necessarily return the primary virtual alias.
221 for(final Iterator<VirtualHost> it = hostDetails.values().iterator(); it.hasNext(); )
222 {
223 final VirtualHost vh = it.next();
224 final String dir = vh.virtualRootDir;
225 if((dir != null) && requestURI.startsWith(dir))
226 { return(vh); }
227 }
228 }
229
230 // Try lookup on the virtual hostname.
231 final VirtualHost result = hostDetails.get(
232 HostUtils.normaliseVirtualHostName(serverHostname));
233 return(result);
234 }
235
236
237 /**Details of one virtual host.
238 * This supports hashCode() and equals() which work on the
239 * (normalised) name alone.
240 */
241 public static final class VirtualHost
242 {
243 /**Construct the record of one virtual host.
244 *
245 * @param hostname non-null name of the host; will be stored normalised
246 * @param root root URI of home directory starting and ending with '/';
247 * if null or "/" (stored as null) then normal home dir is to be used
248 * @param skinName name of livery or skin to be use on each page;
249 * if null or unrecognised then standard livery may be used
250 * @param aliases alias host names for the main host specified
251 * all values supplied will be normalised with duplicates removed;
252 * may be null or zero-length
253 * but entries may not be null or zero-length
254 *
255 * @throws IllegalArgumentException if arguments are malformed
256 */
257 public VirtualHost(final String hostname,
258 final String root,
259 final String skinName,
260 final String[] aliases)
261 {
262 normalisedName = HostUtils.normaliseVirtualHostName(hostname);
263
264 if((root == null) || root.equals("/"))
265 { virtualRootDir = null; }
266 else if(!root.startsWith("/") || !root.endsWith("/"))
267 { throw new IllegalArgumentException(); }
268 else
269 { virtualRootDir = root; }
270
271 final Set<String> normAliases = new HashSet<String>();
272 if(aliases != null)
273 {
274 for(int i = aliases.length; --i >= 0; )
275 {
276 final String a = aliases[i];
277 if(a == null)
278 { throw new IllegalArgumentException("null alias not allowed"); }
279 final String na = HostUtils.normaliseVirtualHostName(a);
280 if(na.length() == 0)
281 { throw new IllegalArgumentException("zero-length (normalised) alias not allowed"); }
282
283 // Only add this alias if not the same as the main name.
284 if(!na.equals(normalisedName))
285 { normAliases.add(na); }
286 }
287 }
288 final Set<String> noAliases = Collections.emptySet();
289 normalisedAliasNames = (normAliases.size() == 0) ? noAliases :
290 Collections.unmodifiableSet(normAliases);
291
292 skin = skinName;
293 }
294
295 /**Normalised (prefix-less, all-lower-case, no-final-dot) virtual host name; non-null. */
296 public final String normalisedName;
297
298 /**Root of virtual host home page in main hierarchy, or null.
299 * Null if normal root (and normal home page) is used,
300 * else starts and ends with '/' but is not "/" and gives position
301 * of opening directory for virtual host.
302 * <p>
303 * The fact that this cannot be "/" makes it safe to do a redirect
304 * without checking the value.
305 */
306 public final String virtualRootDir;
307
308 /**Skin/livery name to be used; null if default is to be used. */
309 public final String skin;
310
311 /**Immutable Set of normalised String hostname aliases for this virtual host; never null.
312 * May be empty.
313 * <p>
314 * Entries are assumed to be deprecated and visitors (and spiders)
315 * arriving at these may be diverted to the normalisedName
316 * to concentrate activity on it.
317 */
318 public final Set<String> normalisedAliasNames;
319
320 /**Return the normalisedName for the String representation. */
321 @Override
322 public String toString() { return(normalisedName); }
323 }
324 }