blob: e733f05624f4acd6b13f05ac5c2deca5b1b0b5e9 [file] [log] [blame]
/*
* 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.felix.http.base.internal.whiteboard;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.servlet.ServletContext;
import org.apache.felix.http.base.internal.context.ExtServletContext;
import org.apache.felix.http.base.internal.registry.HandlerRegistry;
import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceObjects;
import org.osgi.service.http.context.ServletContextHelper;
/**
* The whiteboard context handler provides some information and functionality for
* handling servlet context (helpers).
*/
public class WhiteboardContextHandler implements Comparable<WhiteboardContextHandler>
{
/** The info object for the context. */
private final ServletContextHelperInfo info;
/** The web context. */
private final ServletContext webContext;
/** The http bundle. */
private final Bundle httpBundle;
/** A map of all created servlet contexts. Each bundle gets it's own instance. */
private final Map<Long, ContextHolder> perBundleContextMap = new HashMap<Long, ContextHolder>();
/** The corresponding handler registry. */
private volatile PerContextHandlerRegistry registry;
/** The shared part of the servlet context. */
private volatile ServletContext sharedContext;
public WhiteboardContextHandler(@Nonnull final ServletContextHelperInfo info,
@Nonnull final ServletContext webContext,
@Nonnull final Bundle httpBundle)
{
this.webContext = webContext;
this.info = info;
this.httpBundle = httpBundle;
}
public @Nonnull BundleContext getBundleContext()
{
return this.httpBundle.getBundleContext();
}
public @Nonnull ServletContextHelperInfo getContextInfo()
{
return this.info;
}
@Override
public int compareTo(@Nonnull final WhiteboardContextHandler o)
{
return this.info.compareTo(o.getContextInfo());
}
/**
* Activate this context.
* @return {@code true} if it succeeded.
*/
public boolean activate(@Nonnull final HandlerRegistry registry)
{
this.registry = new PerContextHandlerRegistry(this.info);
this.sharedContext = new SharedServletContextImpl(webContext,
info.getName(),
info.getPath(),
info.getInitParameters(),
this.registry);
final boolean activate = getServletContext(httpBundle) != null;
if ( !activate )
{
this.registry = null;
this.sharedContext = null;
}
else
{
registry.add(this.registry);
}
return activate;
}
/**
* Deactivate this context.
*/
public void deactivate(@Nonnull final HandlerRegistry registry)
{
registry.remove(this.info);
this.registry = null;
this.sharedContext = null;
this.ungetServletContext(httpBundle);
this.perBundleContextMap.clear();
}
public @CheckForNull ServletContext getSharedContext()
{
return sharedContext;
}
public @CheckForNull ExtServletContext getServletContext(@CheckForNull final Bundle bundle)
{
if ( bundle == null )
{
return null;
}
final Long key = bundle.getBundleId();
synchronized ( this.perBundleContextMap )
{
ContextHolder holder = this.perBundleContextMap.get(key);
if ( holder == null )
{
final BundleContext ctx = bundle.getBundleContext();
final ServiceObjects<ServletContextHelper> so = (ctx == null ? null : ctx.getServiceObjects(this.info.getServiceReference()));
if ( so != null )
{
final ServletContextHelper service = so.getService();
if ( service != null )
{
holder = new ContextHolder();
holder.servletContextHelper = service;
holder.servletContext = new PerBundleServletContextImpl(bundle,
this.sharedContext,
service,
this.registry.getEventListenerRegistry());
this.perBundleContextMap.put(key, holder);
}
}
}
if ( holder != null )
{
holder.counter++;
return holder.servletContext;
}
}
return null;
}
public void ungetServletContext(@Nonnull final Bundle bundle)
{
final Long key = bundle.getBundleId();
synchronized ( this.perBundleContextMap )
{
ContextHolder holder = this.perBundleContextMap.get(key);
if ( holder != null )
{
holder.counter--;
if ( holder.counter == 0 )
{
this.perBundleContextMap.remove(key);
if ( holder.servletContextHelper != null )
{
final BundleContext ctx = bundle.getBundleContext();
final ServiceObjects<ServletContextHelper> so = (ctx == null ? null : ctx.getServiceObjects(this.info.getServiceReference()));
if ( so != null )
{
so.ungetService(holder.servletContextHelper);
}
}
}
}
}
}
public @CheckForNull PerContextHandlerRegistry getRegistry()
{
return this.registry;
}
private static final class ContextHolder
{
public long counter;
public ExtServletContext servletContext;
public ServletContextHelper servletContextHelper;
}
}