001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.site; 029 030import org.opencms.main.CmsLog; 031import org.opencms.util.CmsStringUtil; 032 033import java.io.Serializable; 034import java.net.URI; 035 036import org.apache.commons.logging.Log; 037 038/** 039 * A matcher object to compare request data against the configured sites.<p> 040 * 041 * @since 6.0.0 042 */ 043public final class CmsSiteMatcher implements Cloneable, Serializable { 044 045 /** The serial version id. */ 046 private static final long serialVersionUID = -3988887650237005342L; 047 048 /** The logger instance for this class. */ 049 private static final Log LOG = CmsLog.getLog(CmsSiteMatcher.class); 050 051 /** Constant for the "http" port. */ 052 private static final int PORT_HTTP = 80; 053 054 /** Constant for the "https" port. */ 055 private static final int PORT_HTTPS = 443; 056 057 /** Constant for the "http" scheme. */ 058 private static final String SCHEME_HTTP = "http"; 059 060 /** Constant for the "https" scheme. */ 061 private static final String SCHEME_HTTPS = "https"; 062 063 /** Wildcard for string matching. */ 064 private static final String WILDCARD = "*"; 065 066 /** Default matcher that always matches all other Site matchers. */ 067 public static final CmsSiteMatcher DEFAULT_MATCHER = new CmsSiteMatcher(WILDCARD, WILDCARD, 0); 068 069 /** Hashcode buffer to save multiple calculations. */ 070 private Integer m_hashCode; 071 072 /** The hostname (e.g. localhost) which is required to access this site. */ 073 private String m_serverName; 074 075 /** The port (e.g. 80) which is required to access this site. */ 076 private int m_serverPort; 077 078 /** The protocol (e.g. "http", "https") which is required to access this site. */ 079 private String m_serverProtocol; 080 081 /** The time offset. */ 082 private long m_timeOffset; 083 084 /**Redirect (only for aliase). */ 085 private boolean m_redirect = false; 086 087 /** 088 * Construct a new site matcher from a String which should be in default URL notation.<p> 089 * 090 * If no port is provided, the default port 80 or 443 will be used for http or https respectively. 091 * If no protocol is provided, the default protocol "http" will be used. 092 * 093 * @param serverString the String, e.g. http://localhost:8080 094 */ 095 public CmsSiteMatcher(String serverString) { 096 097 this(serverString, 0); 098 } 099 100 /** 101 * Construct a new site matcher from a String which should be in default URL notation.<p> 102 * 103 * If no port is provided, the default port 80 or 443 will be used for http or https respectively. 104 * If no protocol is provided, the default protocol "http" will be used. 105 * 106 * @param serverString the String, e.g. http://localhost:8080 107 * @param timeOffset the time offset 108 */ 109 public CmsSiteMatcher(String serverString, long timeOffset) { 110 111 if (serverString == null) { 112 init(WILDCARD, WILDCARD, 0, timeOffset); 113 return; 114 } 115 // remove whitespace 116 serverString = serverString.trim(); 117 118 // remove fragment and query if present 119 int pos = serverString.indexOf("#"); 120 if (pos > 0) { 121 serverString = serverString.substring(0, pos); 122 } 123 pos = serverString.indexOf("?"); 124 if (pos > 0) { 125 serverString = serverString.substring(0, pos); 126 } 127 // cut trailing "/" 128 if (serverString.endsWith("/")) { 129 serverString = serverString.substring(0, serverString.length() - 1); 130 } 131 int serverPort; 132 String serverProtocol, serverName; 133 // check for protocol 134 pos = serverString.indexOf("://"); 135 if (pos >= 0) { 136 serverProtocol = serverString.substring(0, pos); 137 serverString = serverString.substring(pos + 3); 138 } else { 139 serverProtocol = SCHEME_HTTP; 140 } 141 // check for server name and port 142 pos = serverString.indexOf(":"); 143 if (pos >= 0) { 144 serverName = serverString.substring(0, pos); 145 try { 146 String port = serverString.substring(pos + 1); 147 pos = port.indexOf("/"); 148 if (pos >= 0) { 149 port = port.substring(0, pos); 150 } 151 serverPort = Integer.valueOf(port).intValue(); 152 } catch (NumberFormatException e) { 153 if (SCHEME_HTTPS.equals(serverProtocol)) { 154 serverPort = PORT_HTTPS; 155 } else { 156 serverPort = PORT_HTTP; 157 } 158 } 159 } else { 160 serverName = serverString; 161 if (SCHEME_HTTPS.equals(serverProtocol)) { 162 serverPort = PORT_HTTPS; 163 } else { 164 serverPort = PORT_HTTP; 165 } 166 } 167 168 // cut trailing path in server name 169 pos = serverName.indexOf("/"); 170 if (pos >= 0) { 171 serverName = serverName.substring(0, pos); 172 } 173 174 // initialize members 175 init(serverProtocol, serverName, serverPort, timeOffset); 176 } 177 178 /** 179 * Constructs a new site matcher object.<p> 180 * 181 * @param serverProtocol to protocol required to access this site 182 * @param serverName the server URL prefix to which this site is mapped 183 * @param serverPort the port required to access this site 184 */ 185 public CmsSiteMatcher(String serverProtocol, String serverName, int serverPort) { 186 187 init(serverProtocol, serverName, serverPort, 0); 188 } 189 190 /** 191 * Constructs a new site matcher object.<p> 192 * 193 * @param serverProtocol to protocol required to access this site 194 * @param serverName the server URL prefix to which this site is mapped 195 * @param serverPort the port required to access this site 196 * @param timeOffset the time offset 197 */ 198 public CmsSiteMatcher(String serverProtocol, String serverName, int serverPort, long timeOffset) { 199 200 init(serverProtocol, serverName, serverPort, timeOffset); 201 } 202 203 /** 204 * Returns a clone of this Objects instance.<p> 205 * 206 * @return a clone of this instance 207 */ 208 @Override 209 public Object clone() { 210 211 return new CmsSiteMatcher(m_serverProtocol, m_serverName, m_serverPort, (m_timeOffset / 1000L)); 212 } 213 214 /** 215 * @see java.lang.Object#equals(java.lang.Object) 216 */ 217 @Override 218 public boolean equals(Object obj) { 219 220 if (obj == this) { 221 return true; 222 } 223 if (!(obj instanceof CmsSiteMatcher)) { 224 return false; 225 } 226 // if one of the object is the default matcher the result is always true 227 if ((this == DEFAULT_MATCHER) || (obj == DEFAULT_MATCHER)) { 228 return true; 229 } 230 CmsSiteMatcher other = (CmsSiteMatcher)obj; 231 return (m_serverPort == other.m_serverPort) 232 && m_serverName.equalsIgnoreCase(other.m_serverName) 233 && m_serverProtocol.equals(other.m_serverProtocol); 234 } 235 236 /** 237 * Generates a site matcher equivalent to this one but with a different scheme.<p> 238 * 239 * @param scheme the new scheme 240 * @return the new site matcher 241 */ 242 public CmsSiteMatcher forDifferentScheme(String scheme) { 243 244 try { 245 URI uri = new URI(getUrl()); 246 URI changedUri = new URI(scheme, uri.getAuthority(), uri.getPath(), uri.getQuery(), uri.getFragment()); 247 CmsSiteMatcher res = new CmsSiteMatcher(changedUri.toString(), m_timeOffset); 248 res.setRedirect(m_redirect); 249 return res; 250 } catch (Exception e) { 251 LOG.error(e.getLocalizedMessage(), e); 252 return null; 253 } 254 } 255 256 /** 257 * Returns the hostname (e.g. localhost) which is required to access this site.<p> 258 * 259 * @return the hostname (e.g. localhost) which is required to access this site 260 */ 261 public String getServerName() { 262 263 return m_serverName; 264 } 265 266 /** 267 * Returns the port (e.g. 80) which is required to access this site.<p> 268 * 269 * @return the port (e.g. 80) which is required to access this site 270 */ 271 public int getServerPort() { 272 273 return m_serverPort; 274 } 275 276 /** 277 * Returns the protocol (e.g. "http", "https") which is required to access this site.<p> 278 * 279 * @return the protocol (e.g. "http", "https") which is required to access this site 280 */ 281 public String getServerProtocol() { 282 283 return m_serverProtocol; 284 } 285 286 /** 287 * Returns the time Offset.<p> 288 * 289 * @return the time Offset 290 */ 291 public long getTimeOffset() { 292 293 return m_timeOffset; 294 } 295 296 /** 297 * Returns the url of this site matcher.<p> 298 * 299 * @return the url, i.e. {protocol}://{servername}[:{port}], port appened only if != 80 300 */ 301 public String getUrl() { 302 303 return m_serverProtocol 304 + "://" 305 + m_serverName 306 + (((m_serverPort != PORT_HTTP) && (m_serverPort != PORT_HTTPS)) ? ":" + m_serverPort : ""); 307 } 308 309 /** 310 * @see java.lang.Object#hashCode() 311 */ 312 @Override 313 public int hashCode() { 314 315 if (m_hashCode == null) { 316 m_hashCode = new Integer(toString().hashCode()); 317 } 318 return m_hashCode.intValue(); 319 } 320 321 /** 322 * Is alias to be redirected? 323 * 324 * @return boolean 325 */ 326 public boolean isRedirect() { 327 328 return m_redirect; 329 } 330 331 /** 332 * Set redirect.<p> 333 * 334 * @param redirect boolean 335 */ 336 public void setRedirect(boolean redirect) { 337 338 m_redirect = redirect; 339 } 340 341 /** 342 * @see java.lang.Object#toString() 343 */ 344 @Override 345 public String toString() { 346 347 StringBuffer result = new StringBuffer(32); 348 if ((m_serverProtocol != null) && !(WILDCARD.equals(m_serverProtocol))) { 349 result.append(m_serverProtocol); 350 result.append("://"); 351 } 352 result.append(m_serverName); 353 if ((m_serverPort > 0) 354 && (!(SCHEME_HTTP.equals(m_serverProtocol) && (m_serverPort == PORT_HTTP))) 355 && (!(SCHEME_HTTPS.equals(m_serverProtocol) && (m_serverPort == PORT_HTTPS)))) { 356 result.append(":"); 357 result.append(m_serverPort); 358 } 359 return result.toString(); 360 } 361 362 /** 363 * Sets the hostname (e.g. localhost) which is required to access this site.<p> 364 * 365 * Setting the hostname to "*" is a wildcard that matches all hostnames 366 * 367 * @param serverName the hostname (e.g. localhost) which is required to access this site 368 */ 369 protected void setServerName(String serverName) { 370 371 if (CmsStringUtil.isEmpty(serverName) || (WILDCARD.equals(serverName))) { 372 m_serverName = WILDCARD; 373 } else { 374 m_serverName = serverName.trim(); 375 } 376 } 377 378 /** 379 * Sets the port (e.g. 80) which is required to access this site.<p> 380 * 381 * Setting the port to 0 (zero) is a wildcard that matches all ports 382 * 383 * @param serverPort the port (e.g. 80) which is required to access this site 384 */ 385 protected void setServerPort(int serverPort) { 386 387 m_serverPort = serverPort; 388 if (m_serverPort < 0) { 389 m_serverPort = 0; 390 } 391 } 392 393 /** 394 * Sets the protocol (e.g. "http", "https") which is required to access this site.<p> 395 * 396 * Setting the protocol to "*" is a wildcard that matches all protocols.<p> 397 * 398 * @param serverProtocol the protocol (e.g. "http", "https") which is required to access this site 399 */ 400 protected void setServerProtocol(String serverProtocol) { 401 402 if (CmsStringUtil.isEmpty(serverProtocol) || (WILDCARD.equals(serverProtocol))) { 403 m_serverProtocol = WILDCARD; 404 } else { 405 int pos = serverProtocol.indexOf("/"); 406 if (pos > 0) { 407 m_serverProtocol = serverProtocol.substring(0, pos).toLowerCase(); 408 } else { 409 m_serverProtocol = serverProtocol.toLowerCase().trim(); 410 } 411 } 412 } 413 414 /** 415 * Sets the time Offset in seconds.<p> 416 * 417 * @param timeOffset the time Offset to set 418 */ 419 protected void setTimeOffset(long timeOffset) { 420 421 m_timeOffset = timeOffset * 1000L; 422 } 423 424 /** 425 * Initializes the member variables.<p> 426 * 427 * @param serverProtocol to protocol required to access this site 428 * @param serverName the server URL prefix to which this site is mapped 429 * @param serverPort the port required to access this site 430 * @param timeOffset the time offset 431 */ 432 private void init(String serverProtocol, String serverName, int serverPort, long timeOffset) { 433 434 setServerProtocol(serverProtocol); 435 setServerName(serverName); 436 setServerPort(serverPort); 437 setTimeOffset(timeOffset); 438 } 439}