All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.eclipsesource.jaxrs.publisher.internal.JAXRSConnector Maven / Gradle / Ivy

Go to download

With the connector OSGi services can be published as RESTful web services by simply registering them as OSGi services.

There is a newer version: 5.3.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2012,2015 EclipseSource and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Holger Staudacher - initial API and implementation
 *    ProSyst Software GmbH. - compatibility with OSGi specification 4.2 APIs
 *    Ivan Iliev - Performance Optimizations
 ******************************************************************************/
package com.eclipsesource.jaxrs.publisher.internal;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpService;

import com.eclipsesource.jaxrs.publisher.ApplicationConfiguration;
import com.eclipsesource.jaxrs.publisher.ServletConfiguration;
import com.eclipsesource.jaxrs.publisher.internal.ServiceContainer.ServiceHolder;

public class JAXRSConnector {

  private static final String HTTP_SERVICE_PORT_PROPERTY = "org.osgi.service.http.port";
  private static final String RESOURCE_HTTP_PORT_PROPERTY = "http.port";
  private static final String DEFAULT_HTTP_PORT = "80";

  private final Object lock = new Object();
  private final ServiceContainer httpServices;
  private final ServiceContainer resources;
  private final Map contextMap;
  private final BundleContext bundleContext;
  private final List resourceCache;
  private ServletConfiguration servletConfiguration;
  private final ServiceContainer applicationConfigurations;
  private Configuration configuration;

  JAXRSConnector( BundleContext bundleContext ) {
    this.bundleContext = bundleContext;
    this.configuration = new Configuration( this );
    this.httpServices = new ServiceContainer( bundleContext );
    this.resources = new ServiceContainer( bundleContext );
    this.contextMap = new HashMap();
    this.resourceCache = new ArrayList();
    this.applicationConfigurations = new ServiceContainer( bundleContext );
  }

  void updateConfiguration( Configuration configuration ) {
    synchronized( lock ) {
      this.configuration = configuration;
      doUpdateConfiguration(configuration);
    }
  }

  HttpService addHttpService( ServiceReference reference ) {
    synchronized( lock ) {
      return doAddHttpService( reference );
    }
  }

  ServletConfiguration setServletConfiguration( ServiceReference reference ) {
    if( servletConfiguration == null ) {
      servletConfiguration = ( ServletConfiguration )bundleContext.getService( reference );
      doUpdateServletConfiguration();
      return servletConfiguration;
    }
    return null;
  }

  void unsetServletConfiguration( ServiceReference reference, ServletConfiguration service ) {
    if( servletConfiguration == service ) {
      servletConfiguration = null;
      bundleContext.ungetService( reference );
      doUpdateServletConfiguration();
    }
  }

  ApplicationConfiguration addApplicationConfiguration( ServiceReference reference ) {
    synchronized( lock ) {
      ApplicationConfiguration service = ( ApplicationConfiguration )applicationConfigurations.add( reference ).getService();
      doUpdateAppConfiguration();
      return service;
    }
  }

  void removeApplicationConfiguration( ServiceReference reference, ApplicationConfiguration service ) {
    synchronized( lock ) {
      applicationConfigurations.remove( service );
      doUpdateAppConfiguration();
    }
  }

  private void doUpdateServletConfiguration() {
    ServiceHolder[] services = httpServices.getServices();
    for( ServiceHolder serviceHolder : services ) {
      contextMap.get( serviceHolder.getService() ).updateServletConfiguration( servletConfiguration );
    }
  }

  private void doUpdateAppConfiguration() {
    ServiceHolder[] services = httpServices.getServices();
    for( ServiceHolder serviceHolder : services ) {
      contextMap.get( serviceHolder.getService() ).updateAppConfiguration( applicationConfigurations );
    }
  }

  private void doUpdateConfiguration(Configuration configuration) {
    ServiceHolder[] services = httpServices.getServices();
    for( ServiceHolder serviceHolder : services ) {
      contextMap.get( serviceHolder.getService() ).updateConfiguration( configuration );
    }
  }

  HttpService doAddHttpService( ServiceReference reference ) {
    ServiceHolder serviceHolder = httpServices.add( reference );
    HttpService service = ( HttpService )serviceHolder.getService();
    contextMap.put( service, createJerseyContext( service, configuration, servletConfiguration ) );
    clearCache();
    return service;
  }

  private void clearCache() {
    List cache = new ArrayList( resourceCache );
    resourceCache.clear();
    for( ServiceHolder serviceHolder : cache ) {
      registerResource( serviceHolder );
    }
  }

  void removeHttpService( HttpService service ) {
    synchronized( lock ) {
      doRemoveHttpService( service );
    }
  }

  void doRemoveHttpService( HttpService service ) {
    JerseyContext context = contextMap.remove( service );
    if( context != null ) {
      cacheFreedResources( context );
    }
    httpServices.remove( service );
  }

  private void cacheFreedResources( JerseyContext context ) {
    List freeResources = context.eliminate();
    for( Object resource : freeResources ) {
      resourceCache.add( resources.find( resource ) );
    }
  }

  Object addResource( ServiceReference reference ) {
    synchronized( lock ) {
      return doAddResource( reference );
    }
  }

  private Object doAddResource( ServiceReference reference ) {
    ServiceHolder serviceHolder = resources.add( reference );
    registerResource( serviceHolder );
    return serviceHolder.getService();
  }

  private void registerResource( ServiceHolder serviceHolder ) {
    Object port = getPort( serviceHolder );
    registerResource( serviceHolder, port );
  }

  private Object getPort( ServiceHolder serviceHolder ) {
    Object port = serviceHolder.getReference().getProperty( RESOURCE_HTTP_PORT_PROPERTY );
    if( port == null ) {
      port = bundleContext.getProperty( HTTP_SERVICE_PORT_PROPERTY );
      if( port == null ) {
        port = DEFAULT_HTTP_PORT;
      }
    }
    return port;
  }

  private void registerResource( ServiceHolder serviceHolder, Object port ) {
    HttpService service = findHttpServiceForPort( port );
    if( service != null ) {
      JerseyContext jerseyContext = contextMap.get( service );
      jerseyContext.addResource( serviceHolder.getService() );
    } else {
      cacheResource( serviceHolder );
    }
  }

  private void cacheResource( ServiceHolder serviceHolder ) {
    resourceCache.add( serviceHolder );
  }

  private HttpService findHttpServiceForPort( Object port ) {
    ServiceHolder[] serviceHolders = httpServices.getServices();
    HttpService result = null;
    for( ServiceHolder serviceHolder : serviceHolders ) {
      Object servicePort = getPort( serviceHolder );
      if( servicePort.equals( port ) ) {
        result = ( HttpService )serviceHolder.getService();
      }
    }
    return result;
  }

  void removeResource( Object resource ) {
    synchronized( lock ) {
      doRemoveResource( resource );
    }
  }

  private void doRemoveResource( Object resource ) {
    ServiceHolder serviceHolder = resources.find( resource );
    resourceCache.remove( serviceHolder );
    HttpService httpService = findHttpServiceForPort( getPort( serviceHolder ) );
    removeResourcesFromContext( resource, httpService );
    resources.remove( resource );
  }

  private void removeResourcesFromContext( Object resource, HttpService httpService ) {
    JerseyContext jerseyContext = contextMap.get( httpService );
    if( jerseyContext != null ) {
      jerseyContext.removeResource( resource );
    }
  }

  // For testing purpose
  JerseyContext createJerseyContext( HttpService service,
                                     Configuration configuration,
                                     ServletConfiguration servletConfiguration )
  {
    return new JerseyContext( service, configuration, servletConfiguration, applicationConfigurations );
  }
}