001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.javamoney.moneta.internal;
020
021import org.javamoney.moneta.spi.PriorityServiceComparator;
022import org.osgi.framework.*;
023
024import javax.money.spi.ServiceProvider;
025import java.io.IOException;
026import java.net.URL;
027import java.util.*;
028import java.util.logging.Level;
029import java.util.logging.Logger;
030
031/**
032 * ServiceContext implementation based on OSGI Service mechanisms.
033 */
034public class OSGIServiceProvider implements ServiceProvider{
035
036    private static final Logger LOG = Logger.getLogger(OSGIServiceProvider.class.getName());
037    private static final OSGIServiceComparator REF_COMPARATOR = new OSGIServiceComparator();
038
039    private BundleContext bundleContext;
040
041    public OSGIServiceProvider( BundleContext bundleContext){
042        this.bundleContext = bundleContext;
043    }
044
045    public boolean isInitialized(){
046        return true;
047    }
048
049
050    @Override
051    public int getPriority() {
052        return 10;
053    }
054
055    @Override
056    public <T> T getService(Class<T> serviceType) {
057        LOG.finest("TAMAYA  Loading service: " + serviceType.getName());
058        ServiceReference<T> ref = this.bundleContext.getServiceReference(serviceType);
059        if(ref!=null){
060            return this.bundleContext.getService(ref);
061        }
062        return null;
063    }
064
065    @SuppressWarnings("unchecked")
066    public <T> T create(Class<T> serviceType) {
067        LOG.finest("TAMAYA  Creating service: " + serviceType.getName());
068        ServiceReference<T> ref = this.bundleContext.getServiceReference(serviceType);
069        if(ref!=null){
070            try {
071                return (T)this.bundleContext.getService(ref).getClass().newInstance();
072            } catch (Exception e) {
073                return null;
074            }
075        }
076        return null;
077    }
078
079    @Override
080    public <T> List<T> getServices(Class<T> serviceType) {
081        LOG.finest("TAMAYA  Loading services: " + serviceType.getName());
082        List<ServiceReference<T>> refs = new ArrayList<>();
083        List<T> services = new ArrayList<>(refs.size());
084        try {
085            refs.addAll(this.bundleContext.getServiceReferences(serviceType, null));
086            Collections.sort(refs, REF_COMPARATOR);
087            for(ServiceReference<T> ref:refs){
088                T service = bundleContext.getService(ref);
089                if(service!=null) {
090                    services.add(service);
091                }
092            }
093        } catch (InvalidSyntaxException e) {
094            e.printStackTrace();
095        }
096        try{
097            for(T service:ServiceLoader.load(serviceType)){
098                services.add(service);
099            }
100            return services;
101        } catch (Exception e) {
102            e.printStackTrace();
103        }
104        return services;
105    }
106
107    public Enumeration<URL> getResources(String resource, ClassLoader cl) throws IOException{
108        LOG.finest("TAMAYA  Loading resources: " + resource);
109        List<URL> result = new ArrayList<>();
110        URL url = bundleContext.getBundle()
111                .getEntry(resource);
112        if(url != null) {
113            LOG.finest("TAMAYA  Resource: " + resource + " found in unregistered bundle " +
114                    bundleContext.getBundle().getSymbolicName());
115            result.add(url);
116        }
117        for(Bundle bundle: bundleContext.getBundles()) {
118            url = bundle.getEntry(resource);
119            if (url != null && !result.contains(url)) {
120                LOG.finest("TAMAYA  Resource: " + resource + " found in registered bundle " + bundle.getSymbolicName());
121                result.add(url);
122            }
123        }
124        for(Bundle bundle: bundleContext.getBundles()) {
125            url = bundle.getEntry(resource);
126            if (url != null && !result.contains(url)) {
127                LOG.finest("TAMAYA  Resource: " + resource + " found in unregistered bundle " + bundle.getSymbolicName());
128                result.add(url);
129            }
130        }
131        return Collections.enumeration(result);
132    }
133
134    public static <T> void registerService(Bundle bundle, Class<T> serviceClass, Class<? extends T> implClass) {
135        try {
136            // Load the service class
137            LOG.info("Loaded Service Factory (" + serviceClass.getName() + "): " + implClass.getName());
138            // Provide service properties
139            Hashtable<String, String> props = new Hashtable<>();
140            props.put(Constants.VERSION_ATTRIBUTE, bundle.getVersion().toString());
141            String vendor = bundle.getHeaders().get(Constants.BUNDLE_VENDOR);
142            props.put(Constants.SERVICE_VENDOR, (vendor != null ? vendor : "anonymous"));
143            // Translate annotated @Priority into a service ranking
144            props.put(Constants.SERVICE_RANKING,
145                    String.valueOf(PriorityServiceComparator.getPriority(implClass)));
146
147            // Register the service factory on behalf of the intercepted bundle
148            JDKUtilServiceFactory factory = new JDKUtilServiceFactory(implClass);
149            BundleContext bundleContext = bundle.getBundleContext();
150            bundleContext.registerService(serviceClass.getName(), factory, props);
151            LOG.info("Registered Tamaya service class: " + implClass.getName() + "(" + serviceClass.getName() + ")");
152        } catch (Exception e) {
153            LOG.log(Level.SEVERE, "Failed to load service: " + implClass.getName(), e);
154        }
155    }
156
157    public static <T> void unregisterService(Bundle bundle, Class<T> serviceClass, Class<? extends T> implClass) {
158        try {
159            LOG.fine("Unloading Service (" + serviceClass.getName() + "): " + implClass.getName());
160            ServiceReference<?> ref = bundle.getBundleContext().getServiceReference(implClass);
161            if (ref != null) {
162                bundle.getBundleContext().ungetService(ref);
163            }
164        } catch (Exception e) {
165            LOG.log(Level.SEVERE, "Failed to unload service: " + implClass.getName(), e);
166        }
167    }
168
169    /**
170     * Service factory simply instantiating the configured service.
171     */
172    static class JDKUtilServiceFactory implements ServiceFactory {
173        private final Class<?> serviceClass;
174
175        public JDKUtilServiceFactory(Class<?> serviceClass) {
176            this.serviceClass = serviceClass;
177        }
178
179        @Override
180        public Object getService(Bundle bundle, ServiceRegistration registration) {
181            try {
182                LOG.fine("Creating Service...:" + serviceClass.getName());
183                return serviceClass.newInstance();
184            } catch (Exception ex) {
185                ex.printStackTrace();
186                throw new IllegalStateException("Failed to create service: " + serviceClass.getName(), ex);
187            }
188        }
189
190        @Override
191        public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
192        }
193    }
194
195}