View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2015 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.caravan.hal.docs.impl;
21  
22  import org.apache.commons.lang3.StringUtils;
23  import org.apache.felix.scr.annotations.Activate;
24  import org.apache.felix.scr.annotations.Component;
25  import org.apache.felix.scr.annotations.Deactivate;
26  import org.apache.felix.scr.annotations.Reference;
27  import org.osgi.framework.Bundle;
28  import org.osgi.framework.BundleContext;
29  import org.osgi.framework.BundleEvent;
30  import org.osgi.service.component.ComponentContext;
31  import org.osgi.service.http.HttpService;
32  import org.osgi.service.http.NamespaceException;
33  import org.osgi.util.tracker.BundleTracker;
34  import org.osgi.util.tracker.BundleTrackerCustomizer;
35  import org.slf4j.Logger;
36  import org.slf4j.LoggerFactory;
37  
38  /**
39   * Tracks bundles that contain JSON schema files generated by hal-docs-maven-plugin, and mounts them
40   * via HTTP service to /docs/json-schema/{serviceId}/*.
41   */
42  @Component(immediate = true)
43  public class JsonSchemaBundleTracker implements BundleTrackerCustomizer<String> {
44  
45    /**
46     * Header name that contains the documentation path for the json schema files.
47     */
48    public static final String HEADER_DOMAIN_PATH = "Caravan-HalDocs-DomainPath";
49  
50    /**
51     * prefix for json schema document URLs.
52     */
53    public static final String SCHEMA_URI_PREFIX = "/docs/json-schema";
54  
55    /**
56     * Classpath prefix where JSON schema files are located.
57     */
58    public static final String SCHEMA_CLASSPATH_PREFIX = "JSON-SCHEMA-INF";
59  
60    private static final Logger log = LoggerFactory.getLogger(JsonSchemaBundleTracker.class);
61  
62    private BundleContext bundleContext;
63    private BundleTracker bundleTracker;
64  
65    @Reference
66    private HttpService httpService;
67  
68    @Activate
69    void activate(ComponentContext componentContext) {
70      bundleContext = componentContext.getBundleContext();
71      this.bundleTracker = new BundleTracker<String>(bundleContext, Bundle.ACTIVE, this);
72      this.bundleTracker.open();
73    }
74  
75    @Deactivate
76    void deactivate(ComponentContext componentContext) {
77      this.bundleTracker.close();
78    }
79  
80    @Override
81    public String addingBundle(Bundle bundle, BundleEvent event) {
82      String domainPath = getHalDocsDomainPath(bundle);
83      if (StringUtils.isNotBlank(domainPath)) {
84        String schemaPath = getDocsPath(domainPath);
85  
86        if (log.isInfoEnabled()) {
87          log.info("Mount JSON schema files for {} to {}", bundle.getSymbolicName(), schemaPath);
88        }
89  
90        try {
91          httpService.registerResources(schemaPath, SCHEMA_CLASSPATH_PREFIX,
92              new HttpContextWrapper(httpService.createDefaultHttpContext(), bundle));
93        }
94        catch (NamespaceException ex) {
95          throw new RuntimeException("Unable to mount JSON schema files to " + schemaPath, ex);
96        }
97        return schemaPath;
98      }
99      return null;
100   }
101 
102   @Override
103   public void modifiedBundle(Bundle bundle, BundleEvent event, String schemaPath) {
104     // nothing to do
105   }
106 
107   @Override
108   public void removedBundle(Bundle bundle, BundleEvent event, String schemaPath) {
109     if (schemaPath == null) {
110       return;
111     }
112     if (log.isInfoEnabled()) {
113       log.info("Unmount JSON schema files for {} from {}", bundle.getSymbolicName(), schemaPath);
114     }
115     httpService.unregister(schemaPath);
116   }
117 
118   private String getHalDocsDomainPath(Bundle bundle) {
119     return bundle.getHeaders().get(HEADER_DOMAIN_PATH);
120   }
121 
122   private String getDocsPath(String domainPath) {
123     return SCHEMA_URI_PREFIX + domainPath;
124   }
125 
126 }