/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.sling.auth.core.impl; import org.apache.sling.commons.osgi.PropertiesUtil; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; /** * The <code>PathBasedHolder</code> provides the basic abstraction for managing * authentication handler and authentication requirements in the * {@link SlingAuthenticator} with the following base functionality: * <ul> * <li>Provide location of control through its path fields</li> * <li>Support orderability of instances by being <code>Comparable</code> and * ordering according to the {@link #fullPath} and the * <code>ServiceReference</code> of the provider service</li> * <li>Support {@link #equals(Object)} and {@link #hashCode()} compatible with * the <code>Comparable</code> implementation.</li> * </ul> */ public abstract class PathBasedHolder implements Comparable<PathBasedHolder> { /** * The full registration path of this instance. This is the actual URL with * which this instance has been created. */ protected final String fullPath; /** * The Scheme part of the URL of the {@link #fullPath}. If no scheme is * contained, this field is set to an empty string. */ final String protocol; /** * The host part of the URL of the {@link #fullPath}. If no host is * contained, this field is set to an empty string. */ final String host; /** * The path part of the URL of the {@link #fullPath}. If that URL contains * neither a scheme nor a host, this field is actually set to the same as * {@link #fullPath}. */ final String path; /** * The <code>ServiceReference</code> to the service, which causes this * instance to be created. This may be <code>null</code> if the entry has * been created by the {@link SlingAuthenticator} itself. */ final ServiceReference<?> serviceReference; /** * Sets up this instance with the given configuration URL provided by the * given <code>serviceReference</code>. * <p> * The <code>serviceReference</code> may be <code>null</code> which means * the configuration is created by the {@link SlingAuthenticator} itself. * Instances whose service reference is <code>null</code> are always ordered * behind instances with non-<code>null</code> service references (provided * their path is equal. * * @param url The configuration URL to setup this instance with * @param serviceReference The reference to the service providing the * configuration for this instance. */ protected PathBasedHolder(final String url, final ServiceReference<?> serviceReference) { String path = url; String host = ""; String protocol = ""; // check for protocol prefix in the full path if (path.startsWith("http://") || path.startsWith("https://")) { int idxProtocolEnd = path.indexOf("://"); protocol = path.substring(0, idxProtocolEnd); path = path.substring(idxProtocolEnd + 1); } // check for host prefix in the full path if (path.startsWith("//")) { int idxHostEnd = path.indexOf("/", 2); idxHostEnd = idxHostEnd == -1 ? path.length() : idxHostEnd; if (path.length() > 2) { host = path.substring(2, idxHostEnd); if (idxHostEnd < path.length()) { path = path.substring(idxHostEnd); } else { path = "/"; } } else { path = "/"; } } // assign the fields this.fullPath = url; this.path = path; this.host = host; this.protocol = protocol; this.serviceReference = serviceReference; } /** * Returns a descriptive string of the provider of this instance. The string * is derived from the service reference with which this instance has been * created. If the instance has been created without a service reference it * is ordered the service description of the {@link SlingAuthenticator} is * returned. */ String getProvider() { // assume the commons/auth SlingAuthenticator provides the entry if (serviceReference == null) { return SlingAuthenticator.DESCRIPTION; } final String descr = PropertiesUtil.toString( serviceReference.getProperty(Constants.SERVICE_DESCRIPTION), null); if (descr != null) { return descr; } return "Service " + PropertiesUtil.toString( serviceReference.getProperty(Constants.SERVICE_ID), "unknown"); } /** * Compares this instance to the <code>other</code> PathBasedHolder * instance. Comparison takes into account the {@link #path} first. If they * are not equal the result is returned: If the <code>other</code> path is * lexicographically sorted behind this {@link #path} a value larger than * zero is returned; otherwise a value smaller than zero is returned. * <p> * If the paths are the same, a positive number is returned if the * <code>other</code> service reference is ordered after this service * reference. If the service reference is the same, zero is returned. * <p> * As a special case, zero is returned if <code>other</code> is the same * object as this. * <p> * If this service reference is <code>null</code>, <code>-1</code> is always * returned; if the <code>other</code> service reference is * <code>null</code>, <code>+1</code> is returned. */ @Override public int compareTo(PathBasedHolder other) { // compare the path first, and return if not equal final int pathResult = other.path.compareTo(path); if (pathResult != 0) { return pathResult; } // now compare the service references giving priority to // to the higher priority service if (serviceReference == null) { if ( other.serviceReference == null ) { return this.getClass().getName().compareTo(other.getClass().getName()); } return -1; } else if (other.serviceReference == null) { return 1; } final int serviceResult = other.serviceReference.compareTo(serviceReference); if ( serviceResult != 0 ) { return serviceResult; } return this.getClass().getName().compareTo(other.getClass().getName()); } /** * Returns the hash code of the full path. */ @Override public int hashCode() { return fullPath.hashCode(); } /** * Returns <code>true</code> if the other object is the same as this or if * it is an instance of the same class with the same full path and the same * provider (<code>ServiceReference</code>). */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } else if (obj == null) { return false; } if (obj.getClass() == getClass()) { PathBasedHolder other = (PathBasedHolder) obj; return fullPath.equals(other.fullPath) && ((serviceReference == null && other.serviceReference == null) || (serviceReference != null && serviceReference.equals(other.serviceReference))); } return false; } }