Merge "Add password recovery procedure for default admin user"
[controller.git] / opendaylight / northbound / commons / src / main / java / org / opendaylight / controller / northbound / commons / NorthboundApplication.java
1 /**
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.northbound.commons;
10
11 import java.util.Dictionary;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.Set;
15
16 import javax.ws.rs.core.Application;
17 import javax.ws.rs.ext.ContextResolver;
18 import javax.xml.bind.JAXBContext;
19 import javax.xml.bind.JAXBException;
20 import javax.xml.bind.annotation.XmlRootElement;
21
22 import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
23 import org.opendaylight.controller.northbound.bundlescanner.IBundleScanService;
24 import org.osgi.framework.Bundle;
25 import org.osgi.framework.BundleContext;
26 import org.osgi.framework.BundleReference;
27 import org.osgi.framework.FrameworkUtil;
28 import org.osgi.framework.ServiceException;
29 import org.osgi.framework.ServiceReference;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * Instance of javax.ws.rs.core.Application used to return the classes
35  * that will be instantiated for JAXRS processing. This hooks onto the
36  * bundle scanner service to provide JAXB classes to JAX-RS for prorcessing.
37  */
38 @SuppressWarnings("unchecked")
39 public class NorthboundApplication extends Application {
40     public static final String JAXRS_RESOURCES_MANIFEST_NAME = "Jaxrs-Resources";
41     private static final Logger LOGGER = LoggerFactory.getLogger(NorthboundApplication.class);
42
43     ////////////////////////////////////////////////////////////////
44     //  Application overrides
45     ////////////////////////////////////////////////////////////////
46
47     @Override
48     public Set<Object> getSingletons() {
49         Set<Object> singletons = new HashSet<Object>();
50         singletons.add(new ContextResolver<JAXBContext>() {
51             @Override
52             public JAXBContext getContext(Class<?> type) {
53                 return newJAXBContext();
54             }
55
56         } );
57         singletons.add(new JacksonJaxbJsonProvider());
58         return singletons;
59     }
60
61     @Override
62     public Set<Class<?>> getClasses() {
63         Set<Class<?>> result = new HashSet<Class<?>>();
64         result.addAll(findJAXRSResourceClasses());
65         return result;
66     }
67
68     private BundleContext getBundleContext() {
69         ClassLoader tlcl = Thread.currentThread().getContextClassLoader();
70         Bundle bundle = null;
71
72         if (tlcl instanceof BundleReference) {
73             bundle = ((BundleReference) tlcl).getBundle();
74         } else {
75             LOGGER.warn("Unable to determine the bundle context based on " +
76                         "thread context classloader.");
77             bundle = FrameworkUtil.getBundle(this.getClass());
78         }
79         return (bundle == null ? null : bundle.getBundleContext());
80     }
81
82     private static final IBundleScanService lookupBundleScanner(BundleContext ctx) {
83         ServiceReference svcRef = ctx.getServiceReference(IBundleScanService.class);
84         if (svcRef == null) {
85             throw new ServiceException("Unable to lookup IBundleScanService");
86         }
87         return IBundleScanService.class.cast(ctx.getService(svcRef));
88     }
89
90     private final JAXBContext newJAXBContext() {
91         BundleContext ctx = getBundleContext();
92         IBundleScanService svc = lookupBundleScanner(ctx);
93         try {
94             List<Class<?>> cls = svc.getAnnotatedClasses(ctx,
95                     new String[] { XmlRootElement.class.getPackage().getName() },
96                     true);
97             return JAXBContext.newInstance(cls.toArray(new Class[cls.size()]));
98         } catch (JAXBException je) {
99             LOGGER.error("Error creating JAXBContext", je);
100             return null;
101         }
102     }
103
104     private final Set<Class<?>> findJAXRSResourceClasses() {
105         BundleContext ctx = getBundleContext();
106         String bundleName = ctx.getBundle().getSymbolicName();
107         Set<Class<?>> result = new HashSet<Class<?>>();
108         ServiceException recordException = null;
109         try {
110             IBundleScanService svc = lookupBundleScanner(ctx);
111             result.addAll(svc.getAnnotatedClasses(ctx,
112                     new String[] { javax.ws.rs.Path.class.getName() }, false));
113         } catch (ServiceException se) {
114             recordException = se;
115             LOGGER.debug("Error finding JAXRS resource annotated classes in " +
116                     "bundle: {} error: {}.", bundleName, se.getMessage());
117             // the bundle scan service cannot be lookedup. Lets attempt to
118             // lookup the resources from the bundle manifest header
119             Dictionary<String,String> headers = ctx.getBundle().getHeaders();
120             String header = headers.get(JAXRS_RESOURCES_MANIFEST_NAME);
121             if (header != null) {
122                 for (String s : header.split(",")) {
123                     s = s.trim();
124                     if (s.length() > 0) {
125                         try {
126                             result.add(ctx.getBundle().loadClass(s));
127                         } catch (ClassNotFoundException cnfe) {
128                             LOGGER.error("Cannot load class: {} in bundle: {} " +
129                                     "defined as MANIFEST JAX-RS resource", s, bundleName, cnfe);
130                         }
131                     }
132                 }
133             }
134
135         }
136
137         if (result.size() == 0) {
138             if (recordException != null) {
139                 throw recordException;
140             } else {
141                 throw new ServiceException("No resource classes found in bundle:" +
142                         ctx.getBundle().getSymbolicName());
143             }
144         }
145         return result;
146     }
147
148 }