org.openanzo.datasource.nodecentric.internal.NodeCentricDatasourceFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.openanzo.datasource.nodecentric.internal.NodeCentricDatasourceFactory.java

Source

/*******************************************************************************
 * Copyright (c) 2008 Cambridge Semantics Incorporated.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * File:        $Source$
 * Created by:  Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com </a>)
 * Created on:  Jul 15, 2008
 * Revision:    $Id$
 * 
 * Contributors:
 *     Cambridge Semantics Incorporated - initial API and implementation
 *******************************************************************************/
package org.openanzo.datasource.nodecentric.internal;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;

import org.apache.commons.collections15.multimap.MultiHashMap;
import org.openanzo.cache.ICacheProvider;
import org.openanzo.datasource.DatasourceDictionary;
import org.openanzo.datasource.IAuthorizationService;
import org.openanzo.datasource.IDatasource;
import org.openanzo.datasource.IDatasourceFactory;
import org.openanzo.datasource.nodecentric.ObjectClassDef;
import org.openanzo.exceptions.AnzoException;
import org.openanzo.exceptions.AnzoRuntimeException;
import org.openanzo.exceptions.ExceptionConstants;
import org.openanzo.exceptions.LogUtils;
import org.openanzo.indexer.lucene.LuceneDictionary;
import org.openanzo.jmx.IJMXServiceEndpoint;
import org.openanzo.osgi.IServiceTrackerListener;
import org.openanzo.osgi.OsgiConfigurationUtils;
import org.openanzo.osgi.OsgiServiceTracker;
import org.openanzo.osgi.ServiceActivator;
import org.openanzo.rdf.utils.SerializationConstants;
import org.openanzo.services.IAuthorizationEventListener;
import org.openanzo.services.IStatisticsProvider;
import org.openanzo.services.ServicesDictionary;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.service.metatype.MetaTypeProvider;
import org.osgi.service.metatype.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Activator factory for NodeCentric Datasources
 * 
 * @author Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com</a>)
 * 
 */
public class NodeCentricDatasourceFactory extends ServiceActivator
        implements IDatasourceFactory, ManagedServiceFactory, MetaTypeProvider {
    private static final Logger log = LoggerFactory.getLogger(NodeCentricDatasourceFactory.class);

    private final static ObjectClassDef instanceDef = new ObjectClassDef();

    private final MultiHashMap<IDatasource, ServiceRegistration> serviceRegistrations = new MultiHashMap<IDatasource, ServiceRegistration>();

    private final ConcurrentMap<String, NodeCentricDatasource> datasources = new ConcurrentHashMap<String, NodeCentricDatasource>();

    private OsgiServiceTracker<IAuthorizationEventListener> aclTracker = null;

    private final Set<IAuthorizationEventListener> aclEventListeners = new CopyOnWriteArraySet<IAuthorizationEventListener>();

    private final HashMap<String, Dictionary<? extends Object, ? extends Object>> initializingDatasource = new HashMap<String, Dictionary<? extends Object, ? extends Object>>();

    private NodeCentricDatasourcesJMX jmxExposer = null;

    /** Factory PID for NodecentricDatasource */
    public static final String FACTORY_PID = "org.openanzo.datasource.nodecentric.Factory";

    private ServiceRegistration jmxRegistration = null;

    @Override
    public String getServicePid() {
        return FACTORY_PID;
    }

    @Override
    public String[] getDependencies() {
        return new String[] { ICacheProvider.class.getName() };
    }

    @Override
    protected Collection<String> getServiceClassNames() {
        HashSet<String> scn = new HashSet<String>(super.getServiceClassNames());
        scn.add(ManagedServiceFactory.class.getName());
        scn.add(MetaTypeProvider.class.getName());
        return scn;
    }

    @Override
    public boolean registerService() {
        return false;
    }

    @Override
    public void start(BundleContext bundleContext) throws Exception {
        super.start(bundleContext);

        aclTracker = new OsgiServiceTracker<IAuthorizationEventListener>(
                new IServiceTrackerListener<IAuthorizationEventListener>() {

                    public void unregisterService(IAuthorizationEventListener service) {
                        aclEventListeners.remove(service);
                    }

                    public void registerService(IAuthorizationEventListener service) {
                        aclEventListeners.add(service);
                    }

                    public Class<IAuthorizationEventListener> getComponentType() {
                        return IAuthorizationEventListener.class;
                    }

                }, bundleContext);
        aclTracker.open();
        jmxExposer = new NodeCentricDatasourcesJMX(bundleContext);
        jmxRegistration = context.registerService(new String[] { IJMXServiceEndpoint.class.getName() }, jmxExposer,
                null);
    }

    @Override
    public void stop(BundleContext context) throws Exception {
        super.stop(context);
        if (aclTracker != null) {
            aclTracker.close();
            aclTracker = null;
        }
    }

    public String getName() {
        return FACTORY_PID;
    }

    @Override
    public String getExtraStatus(boolean html) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        if (html) {
            if (datasources.size() > 0) {
                pw.println("<h4><font color='#00cc00'>NodeCentric Datasources:</font></h4>");
                for (NodeCentricDatasource ds : datasources.values()) {
                    try {
                        pw.println("<li>" + URLDecoder.decode(ds.getName(), "UTF-8") + "</li>");
                    } catch (UnsupportedEncodingException e) {
                        log.error(LogUtils.INTERNAL_MARKER,
                                "Should never happen since UTF-8 must be supported by all JVMs on all platforms.",
                                e);
                    }
                    pw.println("<br/>Configuration Properties: ");
                    pw.println("<table border='1'>");
                    for (Enumeration<? extends Object> keys = ds.getConfigurationParameters().keys(); keys
                            .hasMoreElements();) {
                        Object key = keys.nextElement();
                        Object value = ds.getConfigurationParameters().get(key);
                        if (key.toString().toLowerCase().contains("password")
                                && value.toString().startsWith("encrypted:")) {
                            value = "********";
                        }
                        pw.println("<tr><td>" + key.toString() + "</td><td>" + value.toString() + "</td></tr>");
                    }
                    pw.println("</table>");
                }
            }
            if (initializingDatasource.size() > 0) {
                pw.println("<h4><font color='#FFFF00'>NodeCentric Datasources Starting:</font></h4>");
                for (Map.Entry<String, Dictionary<? extends Object, ? extends Object>> entry : initializingDatasource
                        .entrySet()) {
                    pw.println("<li>" + entry.getKey() + "</li>");
                    pw.println("<br/>Configuration Properties: ");
                    pw.println("<table border='1'>");
                    for (Enumeration<? extends Object> keys = entry.getValue().keys(); keys.hasMoreElements();) {
                        Object key = keys.nextElement();
                        Object value = entry.getValue().get(key);
                        pw.println("<tr><td>" + key.toString() + "</td><td>" + value.toString() + "</td></tr>");
                    }
                    pw.println("</table>");
                }

            }
        } else {
            if (datasources.size() > 0) {
                pw.println("NodeCentric Datasources:");
                for (NodeCentricDatasource ds : datasources.values()) {
                    try {
                        pw.println(URLDecoder.decode(ds.getName(), "UTF-8"));
                    } catch (UnsupportedEncodingException e) {
                        log.error(LogUtils.INTERNAL_MARKER,
                                "Should never happen since UTF-8 must be supported by all JVMs on all platforms.",
                                e);
                    }
                }
            }
            if (initializingDatasource.size() > 0) {
                pw.println("NodeCentric Datasources Starting:");
                for (Map.Entry<String, Dictionary<? extends Object, ? extends Object>> entry : initializingDatasource
                        .entrySet()) {
                    pw.println(entry.getKey());
                }
            }
        }
        pw.flush();
        sw.flush();
        return sw.toString();
    }

    @SuppressWarnings("unchecked")
    public void updated(String pid, Dictionary configProperties) throws ConfigurationException {
        try {
            lock.lockInterruptibly();
            if (!datasources.containsKey(pid)) {
                boolean enabled = ServicesDictionary.getEnabled(configProperties);
                if (enabled) {
                    try {
                        OsgiConfigurationUtils.validateConfiguration(instanceDef, configProperties);
                        OsgiConfigurationUtils.updateConfigProperties(configProperties, context);
                        String indexLocation = LuceneDictionary.getIndexLocation(configProperties);
                        if (indexLocation == null) {
                            File root = context.getDataFile(pid);
                            if (!root.exists()) {
                                root.mkdirs();
                            }
                            File indexLocationFile = new File(root, "index");
                            if (!indexLocationFile.exists()) {
                                indexLocationFile.mkdirs();
                            }
                            LuceneDictionary.setIndexLocation(configProperties,
                                    indexLocationFile.getAbsolutePath());
                        }
                        initializingDatasource.put(pid, configProperties);
                        try {
                            NodeCentricDatasource datasource = new NodeCentricDatasource(context, configProperties,
                                    getDependency(ICacheProvider.class), aclEventListeners, eventAdmin);
                            Dictionary<String, String> properties = new Hashtable<String, String>();
                            properties.put(SerializationConstants.isPrimary,
                                    Boolean.toString(datasource.isPrimary()));
                            properties.put(DatasourceDictionary.KEY_DATASOURCE_URI,
                                    datasource.getInstanceURI().toString());
                            serviceRegistrations.put(datasource,
                                    context.registerService(new String[] { NodeCentricDatasource.class.getName(),
                                            IDatasource.class.getName(), IStatisticsProvider.class.getName() },
                                            datasource, properties));
                            IAuthorizationService auth = datasource.getAuthorizationService();
                            if (auth instanceof IAuthorizationEventListener) {
                                serviceRegistrations.put(datasource, context
                                        .registerService(IAuthorizationEventListener.class.getName(), auth, null));
                            }
                            datasources.put(pid, datasource);
                        } finally {
                            initializingDatasource.remove(pid);
                        }
                    } catch (AnzoException ae) {
                        log.error(LogUtils.LIFECYCLE_MARKER, "Error creating new nodecentric datasource", ae);
                        throw new AnzoRuntimeException(ae);
                    }
                }
            }
        } catch (InterruptedException e) {
            throw new AnzoRuntimeException(ExceptionConstants.OSGI.INTERNAL_COMPONENT_ERROR, e);
        } finally {
            lock.unlock();
        }
    }

    public void deleted(String pid) {
        try {
            lock.lockInterruptibly();
            NodeCentricDatasource datasource = datasources.remove(pid);
            if (datasource != null) {
                try {
                    datasource.close(false);
                } catch (AnzoException ae) {
                    log.error(LogUtils.LIFECYCLE_MARKER, "Error closing nodecentric datasource", ae);
                }
                Collection<ServiceRegistration> regs = serviceRegistrations.remove(datasource);
                if (regs != null) {
                    for (ServiceRegistration reg : regs) {
                        reg.unregister();
                    }
                }
            }
        } catch (InterruptedException e) {
            throw new AnzoRuntimeException(ExceptionConstants.OSGI.INTERNAL_COMPONENT_ERROR, e);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void start() {
        Properties props = new Properties();
        props.put(org.osgi.framework.Constants.SERVICE_PID, getServicePid());
        props.put(org.osgi.framework.Constants.SERVICE_DESCRIPTION, getBundleDescription());
        context.registerService(getServiceClassNames().toArray(new String[0]), this, props);
    }

    @Override
    public void stop(boolean bundleStopping) {
        aclTracker.close();
        for (NodeCentricDatasource ds : datasources.values()) {
            try {
                ds.close(bundleStopping);
                Collection<ServiceRegistration> regs = serviceRegistrations.remove(ds);
                if (regs != null) {
                    for (ServiceRegistration reg : regs) {
                        if (!bundleStopping) {
                            reg.unregister();
                        }
                    }
                    regs.clear();
                }
            } catch (AnzoException ae) {
                log.error(LogUtils.LIFECYCLE_MARKER, "Error closing nodecentric datasource", ae);
            }
        }
        datasources.clear();
        if (bundleStopping && jmxRegistration != null) {
            jmxRegistration.unregister();
            jmxRegistration = null;
        }
    }

    public String[] getLocales() {
        return null;
    }

    public ObjectClassDefinition getObjectClassDefinition(String pid, String locale) {
        return instanceDef;
    }
}