org.ms123.common.nucleus.NucleusServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.ms123.common.nucleus.NucleusServiceImpl.java

Source

/**
 * This file is part of SIMPL4(http://simpl4.org).
 *
 *    Copyright [2014] [Manfred Sattler] <manfred@ms123.org>
 *
 * SIMPL4 is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * SIMPL4 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with SIMPL4.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.ms123.common.nucleus;

import java.util.*;
import java.io.File;
import java.io.FileFilter;
import java.sql.Statement;
import java.sql.Connection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Bundle;
import org.ms123.common.nucleus.PostgresqlPersistenceManagerLoader;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.JDOEnhancer;
import flexjson.*;
import org.datanucleus.*;
import org.datanucleus.api.jdo.*;
import org.ms123.common.libhelper.Inflector;
import javax.transaction.UserTransaction;
import javax.transaction.TransactionManager;
import javax.transaction.Status;
import aQute.bnd.annotation.metatype.*;
import aQute.bnd.annotation.component.*;
import org.osgi.framework.BundleContext;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.ms123.common.rpc.PName;
import org.ms123.common.rpc.POptional;
import org.ms123.common.rpc.RpcException;
import org.eclipse.jgit.storage.file.*;
import org.eclipse.jgit.util.*;
import org.datanucleus.store.schema.SchemaTool;
import org.datanucleus.store.schema.SchemaAwareStoreManager;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.ms123.common.system.tm.TransactionService;
import org.ms123.common.git.GitService;
import org.ms123.common.store.StoreDesc;
import org.ms123.common.libhelper.FileSystemClassLoader;
import org.ms123.common.libhelper.BundleDelegatingClassLoader;
import static org.apache.commons.io.FileUtils.readFileToString;
import org.ms123.common.rpc.PDefaultBool;
import static org.ms123.common.rpc.JsonRpcServlet.ERROR_FROM_METHOD;
import static org.ms123.common.rpc.JsonRpcServlet.INTERNAL_SERVER_ERROR;
import static org.ms123.common.rpc.JsonRpcServlet.PERMISSION_DENIED;

@SuppressWarnings("unchecked")
@Component(enabled = true, configurationPolicy = ConfigurationPolicy.optional, immediate = true, properties = {
        "rpc.prefix=nucleus" })
public class NucleusServiceImpl implements org.ms123.common.nucleus.api.NucleusService, EventHandler {

    protected Inflector m_inflector = Inflector.getInstance();

    private Map<StoreDesc, AbstractPersistenceManagerLoader> m_loaders = new HashMap<StoreDesc, AbstractPersistenceManagerLoader>();

    private BundleContext m_bc;
    private TransactionService m_transactionService;
    private ClassLoader m_aidClassLoader;

    private List<AbstractPersistenceManagerLoader> m_openList = new ArrayList();

    final static String[] topics = new String[] { "namespace/installed", "namespace/created", "namespace/preCommit",
            "namespace/preUpdate", "namespace/postUpdate", "namespace/preGet", "namespace/pull",
            "namespace/deleted" };

    protected void activate(BundleContext bundleContext, Map<?, ?> props) {
        try {
            m_bc = bundleContext;
            debug("NucleusServiceImpl.activate:" + bundleContext);
            Dictionary d = new Hashtable();
            d.put(EventConstants.EVENT_TOPIC, topics);
            m_bc.registerService(EventHandler.class.getName(), this, d);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void deactivate() throws Exception {
        System.out.println("NucleusServiceImpl.deactivate");
        closeAll();
    }

    public void handleEvent(Event event) {
        debug("NucleusServiceImpl.Event: " + event);
        try {
            String ns = (String) event.getProperty("namespace");
            if ("namespace/deleted".equals(event.getTopic())) {
                if (ns.startsWith("global")) {
                    close(StoreDesc.getGlobalData());
                } else {
                    close(StoreDesc.getNamespaceData(ns));
                    close(StoreDesc.getNamespaceMeta(ns));
                }
            }
            if ("namespace/preCommit".equals(event.getTopic())) {
                if (ns.startsWith("global")) {
                    close(StoreDesc.getGlobalData());
                } else {
                    close(StoreDesc.getNamespaceData(ns));
                    close(StoreDesc.getNamespaceMeta(ns));
                }
            }
            if ("namespace/preUpdate".equals(event.getTopic())) {
                if (ns.startsWith("global")) {
                    close(StoreDesc.getGlobalData());
                } else {
                    close(StoreDesc.getNamespaceData(ns));
                    close(StoreDesc.getNamespaceMeta(ns));
                }
            }
            if ("namespace/preGet".equals(event.getTopic())) {
                closeAll();
            }
            StoreDesc.init();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }

    public UserTransaction getUserTransaction() {
        UserTransaction utx = m_transactionService.getUserTransaction();
        return utx;
    }

    public TransactionManager getTransactionManager() {
        TransactionManager tm = m_transactionService.getTransactionManager();
        return tm;
    }

    private synchronized void createFactory(StoreDesc sdesc) {
        debug("createFactory:" + sdesc + "/" + m_loaders);
        if (sdesc == null)
            return;
        try {
            if (m_openList.size() > 0) {
                for (AbstractPersistenceManagerLoader p : m_openList) {
                    p.close();
                }
                m_openList.clear();
            }
            if (m_aidClassLoader == null) {
                createAidClassLoader(sdesc.getBaseDir());
            }
            Map<String, Object> props = new HashMap<String, Object>();
            File[] baseDirs = new File[1];
            baseDirs[0] = sdesc.getBaseDir();
            AbstractPersistenceManagerLoader pml = null;
            if (sdesc.getStore().equals(StoreDesc.STORE_RDBMS)) {
                if (sdesc.getVendor().equals(StoreDesc.VENDOR_PG)) {
                    pml = new PostgresqlPersistenceManagerLoader(m_bc, sdesc, baseDirs, m_aidClassLoader, props,
                            m_transactionService);
                } else if (sdesc.getVendor().equals(StoreDesc.VENDOR_HSQL)) {
                    pml = new HsqldbPersistenceManagerLoader(m_bc, sdesc, baseDirs, m_aidClassLoader, props,
                            m_transactionService);
                } else if (sdesc.getVendor().equals(StoreDesc.VENDOR_H2)) {
                    pml = new H2PersistenceManagerLoader(m_bc, sdesc, baseDirs, m_aidClassLoader, props,
                            m_transactionService);
                }
            }
            if (sdesc.getStore().equals(StoreDesc.STORE_FILE)) {
                pml = new FilePersistenceManagerLoader(m_bc, sdesc, baseDirs, m_aidClassLoader, props,
                        m_transactionService);
            }
            if (sdesc.getStore().equals(StoreDesc.STORE_CASSANDRA)) {
                pml = new CassandraPersistenceManagerLoader(m_bc, sdesc, baseDirs, m_aidClassLoader, props,
                        m_transactionService);
            }
            debug("createFactory.pml:" + pml);
            if (pml == null)
                throw new RuntimeException("NucleusServiceImpl.no_loader_for:" + sdesc + " found");
            m_loaders.put(sdesc, pml);
        } catch (Throwable e) {
            throw new RuntimeException("NucleusServiceImpl.createFactory:Cannot create Factory", e);
        }
    }

    public synchronized void closeAll() {
        debug("CloseAll");
        Iterator<StoreDesc> it = m_loaders.keySet().iterator();
        while (it.hasNext()) {
            StoreDesc sd = it.next();
            debug("\tCloseAll:sd:" + sd);
            try {
                _close(sd);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized void close(StoreDesc sdesc) {
        debug("CLOSE:sd1:" + sdesc);
        Iterator<StoreDesc> it = m_loaders.keySet().iterator();
        while (it.hasNext()) {
            StoreDesc sd = it.next();
            debug("\tCLOSE:sd2:" + sd);
            try {
                if (sdesc.getNamespace().equals(sd.getNamespace()) && sdesc.getPack().equals(sd.getPack())) {
                    _close(sd);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        m_loaders.keySet().removeIf(k -> m_loaders.get(k) == null);
        System.out.println("Loaders2:" + m_loaders);
    }

    private void _close(StoreDesc sdesc) {
        debug("Nucleus._close:" + sdesc);
        AbstractPersistenceManagerLoader pml = m_loaders.get(sdesc);
        if (pml != null) {
            try {
                int count = 0;
                while (true) {
                    debug("NucleusServiceImpl._close:status:" + getUserTransaction().getStatus() + "/" + count);
                    if (getUserTransaction().getStatus() != Status.STATUS_ACTIVE) {
                        pml.close();
                        pml = null;
                        break;
                    }
                    count++;
                    Thread.sleep(2000L);
                    if (count > 20)
                        break;
                }
                if (pml != null) {
                    m_openList.add(pml);
                    m_loaders.put(sdesc, null);
                    debug("close:in tx:" + m_openList);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                m_loaders.put(sdesc, null);
            }
        }
    }

    public Class getClass(StoreDesc sdesc, String className) {
        try {
            className = m_inflector.getClassName(className);
            String pack = sdesc.getJavaPackage();
            try {
                ClassLoader cl = getClassLoader(sdesc);
                //System.out.println("GetClass:("+sdesc+"),"+cl+"/"+pack+"."+className);            
                return cl.loadClass(pack + "." + className);
            } catch (Exception e1) {
                debug("NucleusServiceImpl.getClass:" + sdesc + "/pack:" + pack + "/cn:" + className
                        + " not found, trying common_ns");
                try {
                    return m_aidClassLoader.loadClass(StoreDesc.PACK_AID + "." + className);
                } catch (Exception e2) {
                    throw new RuntimeException("NucleusServiceImpl.getClass(:" + className + ")", e1);
                }
            }
        } catch (Exception e) {
            if (e instanceof RuntimeException)
                throw (RuntimeException) e;
            throw new RuntimeException("NucleusServiceImpl.getClass(" + sdesc + "/" + className + "):", e);
        }
    }

    public java.sql.Connection getJdbcConnection(StoreDesc sdesc) {
        if (m_loaders.get(sdesc) == null) {
            createFactory(sdesc);
        }
        AbstractPersistenceManagerLoader pml = m_loaders.get(sdesc);
        javax.jdo.PersistenceManager pm = pml.getPersistenceManagerFactory().getPersistenceManager();
        return (java.sql.Connection) pm.getDataStoreConnection().getNativeConnection();
    }

    public synchronized PersistenceManagerFactory getPersistenceManagerFactory(StoreDesc sdesc) {
        if (m_loaders.get(sdesc) == null) {
            createFactory(sdesc);
        }
        return m_loaders.get(sdesc).getPersistenceManagerFactory();
    }

    public ClassLoader getClassLoader(StoreDesc sdesc) {
        if (m_loaders.get(sdesc) == null) {
            createFactory(sdesc);
        }
        return m_loaders.get(sdesc).getClassLoader();
    }

    public JDOEnhancer getEnhancer(StoreDesc sdesc) {
        AbstractPersistenceManagerLoader pml = m_loaders.get(sdesc);
        if (pml == null) {
            createFactory(sdesc);
            pml = m_loaders.get(sdesc);
        }
        return pml.getEnhancer();
    }

    private void createAidClassLoader(File baseDir) {
        File[] locations = new File[1];
        locations[0] = new File(baseDir, "classes");
        String[] includePattern = new String[1];
        includePattern[0] = "^aid\\..*";
        ClassLoader bundleDelegatingCL = new BundleDelegatingClassLoader(m_bc.getBundle());
        m_aidClassLoader = new FileSystemClassLoader(bundleDelegatingCL, locations, includePattern);
    }

    private void printMap(String header, Map map) {
        debug("----->" + header);
        if (map != null) {
            Iterator it = map.keySet().iterator();
            while (it.hasNext()) {
                Object key = it.next();
                debug("\tkey=" + key + "=" + map.get(key));
            }
        }
        debug("--------------------------------------------------------");
    }

    /*BEGIN JSON-RPC-API*/
    @RequiresRoles("admin")
    public String schemaTool(@PName(StoreDesc.STORE_ID) String storeId, @PName("op") String op,
            @PName("classes") @POptional Set<String> classes,
            @PName("dry") @POptional @PDefaultBool(false) Boolean dry) throws RpcException {
        try {
            closeAll();
            StoreDesc sdesc = StoreDesc.get(storeId);
            if (m_loaders.get(sdesc) == null) {
                createFactory(sdesc);
            }
            return _schemaOp(sdesc, op, classes, dry);
        } catch (Exception e) {
            throw new RpcException(ERROR_FROM_METHOD, INTERNAL_SERVER_ERROR, "NucleusServiceImpl.schemaTool", e);
        }
    }

    /*BEGIN JSON-RPC-API*/
    private synchronized String _schemaOp(StoreDesc sdesc, String op, Set<String> classes, boolean dry)
            throws Exception {
        debug("\t_schemaOp:sd:" + sdesc + " -> " + op + "|classes:" + classes);
        AbstractPersistenceManagerLoader pml = m_loaders.get(sdesc);
        if (pml != null) {
            SchemaTool schemaTool = new SchemaTool();
            JDOPersistenceManagerFactory pmf = (JDOPersistenceManagerFactory) pml.getPersistenceManagerFactory();
            debug("_schemaOp.pmf:" + pmf + "/" + pml);
            PersistenceNucleusContext ctx = pmf.getNucleusContext();
            SchemaAwareStoreManager ssm = (SchemaAwareStoreManager) ctx.getStoreManager();
            if (op.equals("delete")) {
                Properties props = new Properties();
                props.setProperty("completeDdl", "true");
                props.setProperty("autoStartTable", "true");
                File tempFile = null;
                if (dry) {
                    tempFile = File.createTempFile("delete", ".ddl");
                    props.setProperty("ddlFilename", tempFile.toString());
                    props.setProperty("completeDdl", "true");
                }
                if (classes == null) {
                    classes = sdesc.getClasses();
                } else {
                    Set<String> newClasses = new HashSet();
                    for (String cl : classes) {
                        newClasses.add(sdesc.getFQN(cl));
                    }
                    classes = newClasses;
                }
                debug("\tDELETE:" + classes + "/" + tempFile + "|" + props + "|" + ssm);
                pml.deleteSchema(ssm, classes, props);
                if (dry) {
                    String ddl = readFileToString(tempFile);
                    debug(ddl);
                    return ddl;
                } else {
                    close(sdesc);
                }
            } else if (op.equals("validate")) {
                schemaTool.validateSchemaForClasses(ssm, classes);
            } else if (op.equals("create")) {
                Properties props = new Properties();
                File tempFile = null;
                if (dry) {
                    tempFile = File.createTempFile("create", ".ddl");
                    props.setProperty("ddlFilename", tempFile.toString());
                    props.setProperty("completeDdl", "true");
                }
                schemaTool.createSchemaForClasses(ssm, classes);
                if (dry) {
                    return readFileToString(tempFile);
                } else {
                    close(sdesc);
                }
            }
        }
        return null;
    }

    public void close(@PName(StoreDesc.STORE_ID) String storeid) throws RpcException {
        try {
            StoreDesc sdesc = StoreDesc.get(storeid);
            close(sdesc);
        } catch (Exception e) {
            throw new RpcException(ERROR_FROM_METHOD, INTERNAL_SERVER_ERROR, "NucleusServiceImpl.close:", e);
        }
    }

    @Reference(dynamic = true, optional = true)
    public void setTransactionService(TransactionService paramTransactionService) {
        this.m_transactionService = paramTransactionService;
        System.out.println("TransactionServiceImpl.setTransactionService:" + paramTransactionService);
    }

    protected static void debug(String msg) {
        //System.out.println(msg);
        m_logger.debug(msg);
    }

    protected void info(String msg) {
        System.out.println(msg);
        m_logger.info(msg);
    }

    private static final org.slf4j.Logger m_logger = org.slf4j.LoggerFactory.getLogger(NucleusServiceImpl.class);
}