blob: 2cae2485216e2d5d891650e1aeddfe0ec93deebc [file] [log] [blame]
/*
* Copyright 2012 The Apache Software Foundation.
*
* Licensed 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.clerezza.jaxrs.stanbol.webfragements
import org.apache.stanbol.commons.web.base.resource.BaseStanbolResource
import org.apache.wink.osgi.WinkRequestProcessor
import java.util.ArrayList
import java.util.Collections
import javax.servlet.FilterChain
import javax.servlet.Servlet
import javax.servlet.ServletContext
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse
import javax.servlet.http.HttpServlet
import javax.ws.rs.ext.ContextResolver
import javax.ws.rs.ext.Provider
import org.apache.clerezza.osgi.services.ActivationHelper
import org.apache.clerezza.platform.globalmenu.GlobalMenuItem
import org.apache.clerezza.platform.globalmenu.GlobalMenuItemsProvider
import org.apache.felix.scr.annotations._
import org.apache.stanbol.commons.web.base.LinkResource
import org.apache.stanbol.commons.web.base.NavigationLink
import org.apache.stanbol.commons.web.base.ScriptResource
import org.apache.stanbol.commons.web.base.WebFragment
import org.osgi.framework.BundleContext
import org.osgi.framework.ServiceReference
import org.osgi.service.component.ComponentContext
import org.slf4j.scala.Logging
@Component
@Reference(name = "webFragment",
referenceInterface = classOf[WebFragment],
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
policy = ReferencePolicy.DYNAMIC)
//@Service(Array(classOf[Servlet]))
//@Property(name = "alias", value = Array("/stanbol-ugly-servlet-context-initializer"))
@Service(value = Array(classOf[javax.servlet.Filter], classOf[GlobalMenuItemsProvider]))
@Property(name ="pattern", value=Array(".*"))
class WebFragmentRunner extends javax.servlet.Filter with GlobalMenuItemsProvider with Logging {
@Reference
private var winkRequestProcessor: WinkRequestProcessor = _
@Property(name = "org.apache.stanbol.commons.web.alias", value = Array("/"))
final val ALIAS_PROPERTY = "org.apache.stanbol.commons.web.alias";
@Property(name = STATIC_RESOURCES_URL_ROOT_PROPERTY, value = Array("/static"))
final val STATIC_RESOURCES_URL_ROOT_PROPERTY = "org.apache.stanbol.commons.web.static.url";
/**
* The origins allowed for multi-host requests
*/
@Property(name = CORS_ORIGIN, cardinality = 100, value = Array("*"))
final val CORS_ORIGIN = "org.apache.stanbol.commons.web.cors.origin";
@Property(name = CORS_ACCESS_CONTROL_EXPOSE_HEADERS, cardinality = 100, value = Array("Location"))
final val CORS_ACCESS_CONTROL_EXPOSE_HEADERS = "org.apache.stanbol.commons.web.cors.access_control_expose_headers";
private var webFragments: List[WebFragment] = Nil
private var bundleContext: BundleContext = _
private var activator: Option[ActivationHelper] = None
private val linkResources = new ArrayList[LinkResource]();
private val scriptResources = new ArrayList[ScriptResource]();
private val navigationLinks = new ArrayList[NavigationLink]();
private var staticUrlRoot: String = _
private var applicationAlias: String = _
private var corsOrigins : java.util.Set[String] = _
private var exposedHeaders : java.util.Set[String] = _
private var contextResolverImpl : ContextResolverImpl = _
val menuItems = new java.util.HashSet[GlobalMenuItem]
@Activate
def activate(c: ComponentContext) {
staticUrlRoot = c.getProperties().get(
STATIC_RESOURCES_URL_ROOT_PROPERTY).asInstanceOf[String]
applicationAlias = c.getProperties().get(
ALIAS_PROPERTY).asInstanceOf[String];
{
val values = c.getProperties().get(CORS_ORIGIN);
values match {
case s: String => corsOrigins = Collections.singleton(s)
case i: java.lang.Iterable[_] => {
corsOrigins = new java.util.HashSet[String]();
val iter = i.iterator
while (iter.hasNext) {
corsOrigins.add(iter.next().toString)
};
}
}
}
{
val values = c.getProperties().get(CORS_ACCESS_CONTROL_EXPOSE_HEADERS);
values match {
case s: String => exposedHeaders = Collections.singleton(s)
case i: java.lang.Iterable[_] => {
exposedHeaders = new java.util.HashSet[String]();
val iter = i.iterator
while (iter.hasNext) {
exposedHeaders.add(iter.next().toString)
}
}
}
}
synchronized {
println("activating with "+webFragments);
bundleContext = c.getBundleContext
registerFragments()
}
}
@Deactivate
def deactivate(c: ComponentContext) {
synchronized {
unregisterClasses()
activator.foreach(_.stop(c.getBundleContext))
activator = None
}
}
private def registerFragments() {
activator = Some(new ActivationHelper {
for (f <- webFragments) {
import scala.collection.JavaConverters._
for (s <- f.getJaxrsResourceSingletons.asScala) {
//could alos direcly invoke wink as below
registerRootResource(s)
logger.info("Registered: "+s)
}
for (c <- f.getJaxrsResourceClasses.asScala) {
winkRequestProcessor.bindComponentClass(c)
logger.info("Registered class: "+c)
}
}
start (bundleContext)
})
}
private def unregisterClasses() {
for (f <- webFragments) {
import scala.collection.JavaConverters._
for (c <- f.getJaxrsResourceClasses.asScala) {
winkRequestProcessor.unbindComponentClass(c)
logger.info("Unregistered class: "+c)
}
}
}
protected def bindWebFragment(f: WebFragment) {
linkResources.addAll(f.getLinkResources());
scriptResources.addAll(f.getScriptResources());
navigationLinks.addAll(f.getNavigationLinks());
{
import scala.collection.JavaConverters._
for (nl <- f.getNavigationLinks.asScala) {
menuItems.add(new GlobalMenuItem("/"+nl.getPath, nl.getLabel, nl.getLabel, nl.getOrder, "Stanbol"))
}
};
synchronized {
webFragments ::= f
activator.foreach { a =>
unregisterClasses();
a.stop(bundleContext);
registerFragments()
}
}
}
protected def unbindWebFragment(f: WebFragment) {
linkResources.removeAll(f.getLinkResources());
scriptResources.removeAll(f.getScriptResources());
navigationLinks.removeAll(f.getNavigationLinks());
{
import scala.collection.JavaConverters._
for (nl <- f.getNavigationLinks.asScala) {
menuItems.remove(new GlobalMenuItem("/"+nl.getPath, nl.getLabel, nl.getLabel, nl.getOrder, "Stanbol"))
}
};
synchronized {
webFragments = webFragments diff List(f)
activator.foreach { a=>
unregisterClasses()
a.stop(bundleContext);
registerFragments()
}
}
}
//all this servlet stuff is only needed to get the servlet context
//override def init(config: javax.servlet.ServletConfig) {
override def init(config: javax.servlet.FilterConfig) {
val servletContext = config.getServletContext
Collections.sort(linkResources);
Collections.sort(scriptResources);
Collections.sort(navigationLinks);
servletContext.setAttribute(classOf[BundleContext].getName(), bundleContext);
servletContext.setAttribute(BaseStanbolResource.ROOT_URL, applicationAlias);
servletContext.setAttribute(BaseStanbolResource.STATIC_RESOURCES_ROOT_URL, staticUrlRoot);
servletContext.setAttribute(BaseStanbolResource.LINK_RESOURCES, linkResources);
servletContext.setAttribute(BaseStanbolResource.SCRIPT_RESOURCES, scriptResources);
servletContext.setAttribute(BaseStanbolResource.NAVIGATION_LINKS, navigationLinks);
servletContext.setAttribute(CORS_ORIGIN, corsOrigins);
servletContext.setAttribute(CORS_ACCESS_CONTROL_EXPOSE_HEADERS, exposedHeaders);
contextResolverImpl = new ContextResolverImpl(servletContext)
winkRequestProcessor.bindComponent(contextResolverImpl)
}
override def doFilter(request: ServletRequest, response: ServletResponse,
chain: FilterChain){
chain.doFilter(request, response);
}
override def destroy() {
winkRequestProcessor.unbindComponent(contextResolverImpl)
}
def getMenuItems() : java.util.Set[GlobalMenuItem] = {
return menuItems
}
@Provider
class ContextResolverImpl(servletContext: ServletContext) extends ContextResolver[ServletContext] {
def getContext(clazz: Class[_]): ServletContext = {
def wrapped = servletContext;
new ServletContext() {
def getServletContextName() :String = { wrapped.getServletContextName()}
def removeAttribute(name: String) :Unit = { wrapped.removeAttribute(name)}
def setAttribute(name: String, value: Any) :Unit = { wrapped.setAttribute(name, value)}
def getAttributeNames() :java.util.Enumeration[_] = { wrapped.getAttributeNames()}
def getAttribute(name: String) :Object = {
val result = wrapped.getAttribute(name)
if (result != null) {
result
} else {
val serviceReference = bundleContext.getServiceReference(name) //: ServiceReference[Object]
if (serviceReference != null) {
bundleContext.getService(serviceReference).asInstanceOf[Object]
} else null
}
}
def getInitParameterNames() :java.util.Enumeration[_] = { wrapped.getInitParameterNames()}
def getInitParameter(name: String) :String = { wrapped.getInitParameter(name)}
def getServerInfo() :String = { wrapped.getServerInfo()}
def getRealPath(name: String) :String = { wrapped.getRealPath(name)}
def log(message: String, exception: Throwable) :Unit = { wrapped.log(message,exception)}
def log(exception: Exception, message: String) :Unit = { wrapped.log(exception, message)}
def log(message: String) :Unit = { wrapped.log(message)}
@Deprecated
def getServletNames() :java.util.Enumeration[_] = { wrapped.getServletNames()}
@Deprecated
def getServlets() :java.util.Enumeration[_] = { wrapped.getServlets()}
@Deprecated
def getServlet(name: String) :javax.servlet.Servlet = { wrapped.getServlet(name)}
def getNamedDispatcher(name: String) :javax.servlet.RequestDispatcher = { wrapped.getNamedDispatcher(name)}
def getRequestDispatcher(path: String) :javax.servlet.RequestDispatcher = { wrapped.getRequestDispatcher(path)}
def getResourceAsStream(path: String) :java.io.InputStream = { wrapped.getResourceAsStream(path)}
def getResource(path: String) :java.net.URL = { wrapped.getResource(path)}
def getResourcePaths(path: String) :java.util.Set[_] = { wrapped.getResourcePaths(path)}
def getMimeType(file: String) :String = { wrapped.getMimeType(file)}
def getMinorVersion() :Int = { wrapped.getMajorVersion()}
def getMajorVersion() :Int = { wrapped.getMajorVersion()}
def getContext(uripath: String) :javax.servlet.ServletContext = { wrapped.getContext(uripath)}
def getContextPath() :String = { wrapped.getContextPath()}
}
}
}
}