001package systems.dmx.core.osgi;
002
003import systems.dmx.core.impl.CoreServiceImpl;
004import systems.dmx.core.impl.ModelFactoryImpl;
005import systems.dmx.core.impl.PersistenceLayer;
006import systems.dmx.core.service.CoreService;
007import systems.dmx.core.service.ModelFactory;
008import systems.dmx.core.storage.spi.DMXStorage;
009
010import org.osgi.framework.BundleActivator;
011import org.osgi.framework.BundleContext;
012import org.osgi.framework.ServiceReference;
013import org.osgi.service.http.HttpService;
014import org.osgi.util.tracker.ServiceTracker;
015
016import java.util.logging.Level;
017import java.util.logging.Logger;
018
019
020
021public class CoreActivator implements BundleActivator {
022
023    // ---------------------------------------------------------------------------------------------- Instance Variables
024
025    private static BundleContext bundleContext;
026
027    // consumed services
028    private DMXStorage storageService;
029    private static HttpService httpService;
030
031    private ServiceTracker storageServiceTracker;
032    private ServiceTracker httpServiceTracker;
033
034    // provided service
035    private CoreServiceImpl dmx;
036
037    private Logger logger = Logger.getLogger(getClass().getName());
038
039    // -------------------------------------------------------------------------------------------------- Public Methods
040
041
042
043    // **************************************
044    // *** BundleActivator Implementation ***
045    // **************************************
046
047
048
049    @Override
050    public void start(BundleContext bundleContext) {
051        try {
052            logger.info("========== Starting \"DMX Core\" ==========");
053            this.bundleContext = bundleContext;
054            //
055            registerModelFactory();
056            //
057            (storageServiceTracker = createServiceTracker(DMXStorage.class)).open();
058            (httpServiceTracker = createServiceTracker(HttpService.class)).open();
059        } catch (Throwable e) {
060            logger.log(Level.SEVERE, "An error occurred while starting \"DMX Core\":", e);
061            // Note: here we catch anything, also errors (like NoClassDefFoundError).
062            // If thrown through the OSGi container it would not print out the stacktrace.
063            // File Install would retry to start the bundle endlessly.
064        }
065    }
066
067    @Override
068    public void stop(BundleContext bundleContext) {
069        try {
070            logger.info("========== Stopping \"DMX Core\" ==========");
071            storageServiceTracker.close();
072            httpServiceTracker.close();
073            //
074            if (dmx != null) {
075                dmx.shutdown();
076            }
077            // Note: we do not shutdown the DB here.
078            // The DB shuts down itself through the storage bundle's stop() method.
079        } catch (Throwable e) {
080            logger.log(Level.SEVERE, "An error occurred while stopping \"DMX Core\":", e);
081            // Note: here we catch anything, also errors (like NoClassDefFoundError).
082            // If thrown through the OSGi container it would not print out the stacktrace.
083        }
084    }
085
086    // ---
087
088    public static CoreService getCoreService() {
089        return getService(CoreService.class);
090    }
091
092    public static ModelFactory getModelFactory() {
093        return getService(ModelFactory.class);
094    }
095
096    public static HttpService getHttpService() {
097        return httpService;
098    }
099
100    // ---
101
102    public static <S> S getService(Class<S> clazz) {
103        S serviceObject = bundleContext.getService(bundleContext.getServiceReference(clazz));
104        if (serviceObject == null) {
105            throw new RuntimeException("Service \"" + clazz.getName() + "\" is not available");
106        }
107        return serviceObject;
108    }
109
110
111
112    // ------------------------------------------------------------------------------------------------- Private Methods
113
114    private void registerModelFactory() {
115        logger.info("Registering ModelFactory service at OSGi framework");
116        bundleContext.registerService(ModelFactory.class.getName(), new ModelFactoryImpl(), null);
117    }
118
119    // ---
120
121    private ServiceTracker createServiceTracker(final Class serviceInterface) {
122        //
123        return new ServiceTracker(bundleContext, serviceInterface.getName(), null) {
124
125            @Override
126            public Object addingService(ServiceReference serviceRef) {
127                Object service = null;
128                try {
129                    service = super.addingService(serviceRef);
130                    addService(service);
131                } catch (Throwable e) {
132                    logger.log(Level.SEVERE, "An error occurred while adding service " + serviceInterface.getName() +
133                        " to \"DMX Core\":", e);
134                    // Note: here we catch anything, also errors (like NoClassDefFoundError).
135                    // If thrown through the OSGi container it would not print out the stacktrace.
136                }
137                return service;
138            }
139
140            @Override
141            public void removedService(ServiceReference ref, Object service) {
142                try {
143                    removeService(service);
144                    super.removedService(ref, service);
145                } catch (Throwable e) {
146                    logger.log(Level.SEVERE, "An error occurred while removing service " + serviceInterface.getName() +
147                        " from \"DMX Core\":", e);
148                    // Note: here we catch anything, also errors (like NoClassDefFoundError).
149                    // If thrown through the OSGi container it would not print out the stacktrace.
150                }
151            }
152        };
153    }
154
155    // ---
156
157    private void addService(Object service) {
158        if (service instanceof DMXStorage) {
159            logger.info("Adding storage service to DMX Core");
160            storageService = (DMXStorage) service;
161            checkRequirementsForActivation();
162        } else if (service instanceof HttpService) {
163            logger.info("Adding HTTP service to DMX Core");
164            httpService = (HttpService) service;
165            checkRequirementsForActivation();
166        }
167    }
168
169    private void removeService(Object service) {
170        if (service == storageService) {
171            logger.info("Removing storage service from DMX Core");
172            storageService = null;
173        } else if (service == httpService) {
174            logger.info("Removing HTTP service from DMX Core");
175            httpService = null;
176        }
177    }
178
179    // ---
180
181    private void checkRequirementsForActivation() {
182        if (storageService != null && httpService != null) {
183            dmx = new CoreServiceImpl(new PersistenceLayer(storageService), bundleContext);
184            //
185            logger.info("Registering DMX core service at OSGi framework");
186            bundleContext.registerService(CoreService.class.getName(), dmx, null);
187        }
188    }
189}