/** * Copyright 2014-2017 Linagora, Université Joseph Fourier, Floralis * * The present code is developed in the scope of the joint LINAGORA - * Université Joseph Fourier - Floralis research program and is designated * as a "Result" pursuant to the terms and conditions of the LINAGORA * - Université Joseph Fourier - Floralis research program. Each copyright * holder of Results enumerated here above fully & independently holds complete * ownership of the complete Intellectual Property rights applicable to the whole * of said Results, and may freely exploit it in any manner which does not infringe * the moral rights of the other copyright holders. * * 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 net.roboconf.dm.rest.services.internal; import java.util.Dictionary; import java.util.Hashtable; import java.util.logging.Logger; import javax.servlet.Filter; import org.ops4j.pax.url.mvn.MavenResolver; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.osgi.service.http.HttpService; import com.sun.jersey.spi.container.servlet.ServletContainer; import net.roboconf.core.utils.Utils; import net.roboconf.dm.management.Manager; import net.roboconf.dm.rest.commons.security.AuthenticationManager; import net.roboconf.dm.rest.services.internal.filters.AuthenticationFilter; import net.roboconf.dm.rest.services.internal.icons.IconServlet; import net.roboconf.dm.rest.services.internal.websocket.RoboconfWebSocketServlet; import net.roboconf.dm.scheduler.IScheduler; /** * An iPojo component in charge of injecting the Manager into the REST services. * <p> * This class also registers and unregisters these REST resources within the * HTTP service of the OSGi container. * </p> * * @author Vincent Zurczak - Linagora */ public class ServletRegistrationComponent { // Constants public static final String REST_CONTEXT = "/roboconf-dm"; public static final String WEBSOCKET_CONTEXT = "/roboconf-dm-websocket"; static final String ICONS_CONTEXT = "/roboconf-icons"; // Injected by iPojo private HttpService httpService; private Manager manager; private IScheduler scheduler; private MavenResolver mavenResolver; private boolean enableCors = false; private boolean enableAuthentication = false; private long sessionPeriod; // Internal fields private final Logger logger = Logger.getLogger( getClass().getName()); private final BundleContext bundleContext; RestApplication app; ServletContainer jerseyServlet; ServiceRegistration<Filter> filterServiceRegistration; AuthenticationFilter authenticationFilter; AuthenticationManager authenticationMngr; /** * Constructor. * @param bundleContext */ public ServletRegistrationComponent( BundleContext bundleContext ) { this.bundleContext = bundleContext; } /** * The method to use when all the dependencies are resolved. * <p> * It means iPojo guarantees that both the manager and the HTTP * service are not null. * </p> * * @throws Exception in case of critical error */ public void starting() throws Exception { this.logger.fine( "iPojo registers REST and icons servlets related to Roboconf's DM." ); // Create the REST application with its resources. // The scheduler may be null, it is optional. this.app = new RestApplication( this.manager ); this.app.setScheduler( this.scheduler ); this.app.setMavenResolver( this.mavenResolver ); this.app.enableCors( this.enableCors ); this.app.setAuthenticationManager( this.authenticationMngr ); Dictionary<String,String> initParams = new Hashtable<> (); initParams.put( "servlet-name", "Roboconf DM (REST)" ); this.jerseyServlet = new ServletContainer( this.app ); this.httpService.registerServlet( REST_CONTEXT, this.jerseyServlet, initParams, null ); // Deal with the icons servlet initParams = new Hashtable<> (); initParams.put( "servlet-name", "Roboconf DM (icons)" ); IconServlet iconServlet = new IconServlet( this.manager ); this.httpService.registerServlet( ICONS_CONTEXT, iconServlet, initParams, null ); // Register the web socket initParams = new Hashtable<> (); initParams.put( "servlet-name", "Roboconf DM (websocket)" ); RoboconfWebSocketServlet websocketServlet = new RoboconfWebSocketServlet(); this.httpService.registerServlet( WEBSOCKET_CONTEXT, websocketServlet, initParams, null ); // Register a filter for authentication this.authenticationFilter = new AuthenticationFilter(); this.authenticationFilter.setAuthenticationEnabled( this.enableAuthentication ); this.authenticationFilter.setAuthenticationManager( this.authenticationMngr ); this.authenticationFilter.setSessionPeriod( this.sessionPeriod ); this.authenticationFilter.setEnableCors( this.enableCors ); initParams = new Hashtable<> (); initParams.put( "urlPatterns", "*" ); // Consider the bundle context can be null (e.g. when used outside of OSGi) if( this.bundleContext != null ) this.filterServiceRegistration = this.bundleContext.registerService( Filter.class, this.authenticationFilter, initParams ); else this.logger.warning( "No bundle context was available, the authentication filter was not registered." ); } /** * The method to use when dependencies are invalidated. * @throws Exception in case of critical error */ public void stopping() throws Exception { // Remove the filter if( this.filterServiceRegistration != null ) this.filterServiceRegistration.unregister(); // Update the HTTP service this.logger.fine( "iPojo unregisters REST and icons servlets related to Roboconf's DM." ); if( this.httpService != null ) { this.httpService.unregister( REST_CONTEXT ); this.httpService.unregister( ICONS_CONTEXT ); this.httpService.unregister( WEBSOCKET_CONTEXT ); } else { this.logger.fine( "The HTTP service is gone. The servlets were already unregistered." ); } // Reset the application this.app = null; this.jerseyServlet = null; this.filterServiceRegistration = null; this.authenticationFilter = null; } /** * Invoked by iPojo when the scheduler appears. * @throws Exception in case of error */ public void schedulerAppears() throws Exception { // We simply update the "scheduler" resource. this.logger.fine( "Roboconf's scheduler is here. Updating the REST resource." ); if( this.app != null ) this.app.setScheduler( this.scheduler ); } /** * Invoked by iPojo when the scheduler disappears. * @throws Exception in case of error */ public void schedulerDisappears() throws Exception { // We simply update the "scheduler" resource. this.logger.fine( "Roboconf's scheduler vanished. Updating the REST resource." ); if( this.app != null ) this.app.setScheduler( null ); } /** * Invoked by iPojo when the Maven resolver appears. * @throws Exception in case of error */ public void mavenResolverAppears() throws Exception { // We simply update the "urlResolver" resource. this.logger.fine( "Roboconf's URL resolver is here. Updating the REST resource." ); if( this.app != null ) this.app.setMavenResolver( this.mavenResolver ); } /** * Invoked by iPojo when the Maven resolver disappears. * @throws Exception in case of error */ public void mavenResolverDisappears() throws Exception { // We simply update the "urlResolver" resource. this.logger.fine( "Roboconf's URL resolver vanished. Updating the REST resource." ); if( this.app != null ) this.app.setMavenResolver( null ); } /** * @param httpService the httpService to set */ public void setHttpService( HttpService httpService ) { this.httpService = httpService; } /** * @param manager the manager to set */ public void setManager( Manager manager ) { this.manager = manager; } /** * Invoked by iPojo. * @param enableCors the enableCors to set */ public void setEnableCors( boolean enableCors ) { this.logger.fine( "CORS is now " + (enableCors ? "enabled" : "disabled") + ". Updating the REST resource." ); this.enableCors = enableCors; if( this.app != null ) this.app.enableCors( enableCors ); if( this.authenticationFilter != null ) this.authenticationFilter.setEnableCors( enableCors ); try { if( this.jerseyServlet != null ) this.jerseyServlet.reload(); } catch( Exception e ) { Utils.logException( this.logger, e ); } } /** * Invoked by iPojo. * @param enableAuthentication the enableAuthentication to set */ public void setEnableAuthentication( boolean enableAuthentication ) { this.logger.fine( "Authentication is now " + (enableAuthentication ? "enabled" : "disabled") + ". Updating the REST resource." ); this.enableAuthentication = enableAuthentication; if( this.authenticationFilter != null ) this.authenticationFilter.setAuthenticationEnabled( enableAuthentication ); } /** * @param authenticationRealm the authenticationRealm to set */ public void setAuthenticationRealm( String authenticationRealm ) { // Given the way sessions are stored in AuthenticationManager (private map), // changing the realm will invalidate all the current sessions this.logger.fine( "New authentication realm: " + authenticationRealm ); this.authenticationMngr = new AuthenticationManager( authenticationRealm ); // Propagate the change if( this.authenticationFilter != null ) this.authenticationFilter.setAuthenticationManager( this.authenticationMngr ); if( this.app != null ) this.app.setAuthenticationManager( this.authenticationMngr ); } /** * @param sessionPeriod the sessionPeriod to set */ public void setSessionPeriod( long sessionPeriod ) { this.logger.fine( "New session period: " + sessionPeriod ); this.sessionPeriod = sessionPeriod; if( this.authenticationFilter != null ) this.authenticationFilter.setSessionPeriod( sessionPeriod ); } // These setters are not used by iPojo. // But they may be useful when using this class outside OSGi. /** * @param scheduler the scheduler to set */ public void setScheduler( IScheduler scheduler ) { this.scheduler = scheduler; } /** * @param mavenResolver the Maven resolver to set */ public void setMavenResolver( MavenResolver mavenResolver ) { this.mavenResolver = mavenResolver; } }