/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2009-2010 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can * obtain a copy of the License at * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package com.sun.grizzly.osgi.httpservice; import com.sun.grizzly.tcp.http11.GrizzlyAdapter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.osgi.service.http.HttpContext; import javax.servlet.Servlet; import java.util.concurrent.locks.ReentrantLock; /** * Context mapper. * Supports complex context. * * @author Hubert Iwaniuk */ class OSGiCleanMapper { private static final ReentrantLock lock = new ReentrantLock(); private static final TreeSet<String> aliasTree = new TreeSet<String>(); private static final Map<String, GrizzlyAdapter> registrations = new HashMap<String, GrizzlyAdapter>(16); private static final Set<Servlet> registeredServlets = new HashSet<Servlet>(16); private Set<String> localAliases = new HashSet<String>(4); private HashMap<HttpContext, ArrayList<OSGiServletAdapter>> contextServletAdapterMap = new HashMap<HttpContext, ArrayList<OSGiServletAdapter>>(3); /** * Performs mapping of requested URI to registered alias if any. * <p/> * Works in two modes: * <ul> * <li>Full match - Checks for full match of resource (cutAfterSlash == false),</li> * <li>Reducing match - Checks {@link String#substring(int, int)} (0, {@link String#lastIndexOf(String)} ('/')) * for match (cutAfterSlash == true).</li> * </ul> * * @param resource Resource to be mapped. * @param cutAfterSlash Should cut off after last '/' before looking up. * @return First matching alias, or <code>null</code> if no match has been found. */ public static String map(String resource, boolean cutAfterSlash) { String result; String match = resource; while (true) { int i = 0; if (cutAfterSlash) { i = match.lastIndexOf('/'); if (i == -1) { result = null; break; } else { if (i == 0) match = "/"; else match = resource.substring(0, i); } } if (containsAlias(match)) { result = match; break; } else if (i == 0) { result = null; break; } } return result; } /** * Checks if alias has been registered. * * @param alias Alias to check. * @return <code>true</code> iff alias has been registered, else <code>false</code>. */ public static boolean containsAlias(String alias) { return aliasTree.contains(alias); } /** * Checks if {@link Servlet} has been registered. * * @param servlet Servlet instance to check. * @return <code>true</code> iff alias has been registered, else <code>false</code>. */ public static boolean contaisServlet(Servlet servlet) { return registeredServlets.contains(servlet); } /** * Gets mappers {@link ReentrantLock}. * <p/> * This {@link java.util.concurrent.locks.Lock} should protect mappers state. * * @return {@link java.util.concurrent.locks.Lock} to protect operations on mapper. */ public static ReentrantLock getLock() { return lock; } /** * Looksup {@link GrizzlyAdapter} registered under alias. * * @param alias Registered alias. * @return {@link GrizzlyAdapter} registered under alias. */ static GrizzlyAdapter getAdapter(String alias) { return registrations.get(alias); } /** * Remove registration information for internal book keeping. * * @param alias Alias to unregister. */ public void recycleRegistrationData(String alias) { if (containsAlias(alias)) { // global cleanup aliasTree.remove(alias); GrizzlyAdapter adapter = registrations.remove(alias); adapter.destroy(); // local cleanup localAliases.remove(alias); } else { // already gone } } /** * Add {@link com.sun.grizzly.tcp.http11.GrizzlyAdapter}. * <p/> * * @param alias Registration alias. * @param adapter Adapter handling requests for <code>alias</code>. */ public void addGrizzlyAdapter(String alias, GrizzlyAdapter adapter) { if (containsAlias(alias)) { // should not happend, alias should be checked before. // TODO: signal it some how } else { registerAliasAdapter(alias, adapter); if (adapter instanceof OSGiServletAdapter) { registeredServlets.add(((OSGiServletAdapter) adapter).getServletInstance()); } localAliases.add(alias); } } /** * Checks if alias was registered by calling bundle. * * @param alias Alias to check for local registration. * @return <code>true</code> iff alias was registered localy, else <code>false</code>. */ public boolean isLocalyRegisteredAlias(String alias) { return localAliases.contains(alias); } /** * Executes unregistering of <code>alias</code> optionally calling {@link javax.servlet.Servlet#destroy()}. * * @param alias Alias to unregister. * @param callDestroyOnServlet If <code>true</code> call {@link javax.servlet.Servlet#destroy()}, else don't call. */ public void doUnregister(String alias, boolean callDestroyOnServlet) { if (containsAlias(alias)) { GrizzlyAdapter adapter = getAdapter(alias); if (adapter instanceof OSGiServletAdapter) { ((OSGiGrizzlyAdapter) adapter).getRemovalLock().lock(); try { Servlet servlet = ((OSGiServletAdapter) adapter).getServletInstance(); registeredServlets.remove(servlet); if (callDestroyOnServlet) { servlet.destroy(); } } finally { ((OSGiGrizzlyAdapter) adapter).getRemovalLock().unlock(); } } } recycleRegistrationData(alias); } /** * Gets localy registered aliases. * * @return Unmodidiable {@link Set} of localy registered aliases. */ public Set<String> getLocalAliases() { return Collections.unmodifiableSet(localAliases); } /** * Gets all registered aliases. * * @return {@link Set} of all registered aliases. */ /*package*/ static Set<String> getAllAliases() { return aliasTree; } /** * Checks if {@link HttpContext} has been registered.. * * @param httpContext Context to check. * @return <code>true</code> iff httpContext has been registered. */ public boolean containsContext(HttpContext httpContext) { return contextServletAdapterMap.containsKey(httpContext); } public List<OSGiServletAdapter> getContext(HttpContext httpContext) { return contextServletAdapterMap.get(httpContext); } public void addContext(HttpContext httpContext, ArrayList<OSGiServletAdapter> servletAdapters) { contextServletAdapterMap.put(httpContext, servletAdapters); } private static boolean registerAliasAdapter(String alias, GrizzlyAdapter adapter) { boolean wasNew = aliasTree.add(alias); if (wasNew) { registrations.put(alias, adapter); } else { // TODO already registered, wtf } return wasNew; } }