Package com.dotmarketing.portlets.chains.business

Source Code of com.dotmarketing.portlets.chains.business.ChainAPIImpl$ChainLinkClassLoader

package com.dotmarketing.portlets.chains.business;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.dotmarketing.business.DotCacheException;
import com.dotmarketing.business.FactoryLocator;
import com.dotmarketing.compilers.DotCompilationProblems;
import com.dotmarketing.compilers.DotJdtCompiler;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.exception.DotRuntimeException;
import com.dotmarketing.portlets.chains.ChainLink;
import com.dotmarketing.portlets.chains.model.Chain;
import com.dotmarketing.portlets.chains.model.ChainLinkCode;
import com.dotmarketing.portlets.chains.model.ChainState;
import com.dotmarketing.portlets.chains.model.ChainStateParameter;
import com.dotmarketing.portlets.chains.model.ChainLinkCode.Language;

/**
*
* @author davidtorresv
*
*/
public class ChainAPIImpl implements ChainAPI {

  /**
   * This is a private class loader used internally by this class to dynamically instanciate
   * and manage chain links
   *
   * @author davidtorresv
   *
   */
  private class ChainLinkClassLoader extends ClassLoader {
   
    ClassLoader cl;
    public ChainLinkClassLoader(ClassLoader contextClassloader) {
      cl = contextClassloader;
    }
   
      public byte[] findClassBytes(String className, String currentRoot){

          try{
              String pathName = currentRoot +
                  File.separatorChar + className.replace('.', File.separatorChar) + ".class";
              FileInputStream inFile = new
                  FileInputStream(pathName);
              byte[] classBytes = new
                  byte[inFile.available()];
              inFile.read(classBytes);
              return classBytes;
          }
          catch (java.io.IOException ioEx){
              return null;
          }
      }

      @Override
    protected Class<?> findClass(String name)
          throws ClassNotFoundException {
     
      File codeDir = new File(buildFilePath);
      if(!codeDir.exists()) {
        if(!codeDir.mkdirs())
          throw new ClassNotFoundException(name, new Exception("Couldn't create the compilation folder for links path: " + buildFilePath));
      }
      byte[] classBytes = findClassBytes(name, buildFilePath);
          if (classBytes==null){
            //If the class doesn't exist on the links compilation folder then
            // the class loader will use the context classloader given on the constructor
              return cl.loadClass(name);
          }
          else{
              return defineClass(name, classBytes, 0, classBytes.length);
          }
    }
       

  }

  private ClassLoader linksClassLoader;
  private String buildFilePath = System.getProperty("java.io.tmpdir") + File.separator + "_dotcms_" +
    File.separator + "links" + File.separator + "build";
  private ChainFactory chainFactory = FactoryLocator.getChainFactory();

  public ChainAPIImpl () {
    linksClassLoader = new ChainLinkClassLoader(Thread.currentThread().getContextClassLoader());
    chainFactory = FactoryLocator.getChainFactory();
  }
 
  public ChainLink instanciateChainLink(long linkCodeId) throws DotRuntimeException, DotDataException, DotCacheException {
 
    //Looking for the chain link code using the factory
    ChainLinkCode linkCode = chainFactory.loadChainLinkCode(linkCodeId);
    if(linkCode == null)
      throw new DotRuntimeException("Link code id: " + linkCodeId + ", not found.");

    try {
      return instanciateChainLink(linkCode);
    } catch (ChainLinkCodeCompilationException e) {
      throw new DotRuntimeException(e.getMessage(), e);
    }
  }

  private ChainLink instanciateChainLink(ChainLinkCode linkCode) throws ChainLinkCodeCompilationException, DotRuntimeException, DotDataException, DotCacheException {
 
    if(!Language.JAVA.equals(linkCode.getLanguage()))
      throw new ChainLinkCodeCompilationException("Only Java language is now supported", null);
   
    String className = linkCode.getClassName();
   
    //Initializing path variables
        String javaFilePath = buildFilePath +
          File.separatorChar + className.replace('.', File.separatorChar) + ".java";
        File javaFile = new File(javaFilePath);

        String classFilePath = buildFilePath +
        File.separatorChar + className.replace('.', File.separatorChar) + ".class";
        File classFile = new File(classFilePath);
      
        //If the compiled class file doesn't exist or the link code in the database is newer
        // then we need to recompile
        if(!classFile.exists() || new Date(classFile.lastModified()).compareTo(linkCode.getLastModifiedDate()) < 0) {
         
          if(javaFile.exists()) {
            //If the class file already exists means that code already compiled is old we need to drop the
            //actual classloader to force the class reloading
            if (!javaFile.delete()) {
          throw new DotRuntimeException("Couldn't remove the old file to compile the new code on the link id: " + linkCode.getId());            
            }
              //Need to drop the classloader to force a class reload
            linksClassLoader = new ChainLinkClassLoader(Thread.currentThread().getContextClassLoader());
          }
         
          //Creating the java file to save the java code in the file
        try {
                File parentFolder = new File(new File(javaFilePath).getParent());
                if(!parentFolder.exists())
                  parentFolder.mkdirs();
        if (!javaFile.createNewFile()) {
          throw new DotRuntimeException("Couldn't create the file to compile the code link id: " + linkCode.getId());            
        }
      } catch (IOException e) {
        throw new DotRuntimeException("Couldn't create the file to compile the code link id: " + linkCode.getId());            
      }
     
      //Saving the java code in the file
      PrintWriter pw = null;
      try {
        pw = new PrintWriter(javaFilePath);
        pw.write(linkCode.getCode());
        pw.flush();
      } catch (IOException e) {
        throw new DotRuntimeException("Couldn't create the file to compile the code link id: " + linkCode.getId());            
      } finally {
        if (pw != null) pw.close();
     
     
      //Compiling the java code
      try {
        DotCompilationProblems problems = DotJdtCompiler.compileClass(javaFilePath, linkCode.getClassName(), buildFilePath);
        //If java code compilation problems are found then a DotRuntime Exception is thrown with the compilation errors in it
        if(problems.hasCompilationErrors()) {
          throw new ChainLinkCodeCompilationException("A compilation error has ocurred when compiling your link code", problems);
        }
      } catch (FileNotFoundException e) {
        throw new DotRuntimeException("Error ocurred trying to compile the link code." , e);
      }
     
        }
   
        ChainLink instance = null;
        try {
       instance = (ChainLink) linksClassLoader.loadClass(linkCode.getClassName()).newInstance();
       instance.setCode(linkCode);
    } catch (ClassNotFoundException e) {
      throw new DotRuntimeException("Unable to load the class for link code id: " + linkCode.getId() + ".", e);
    } catch (InstantiationException e) {
      throw new DotRuntimeException("Unable to load the class for link code id: " + linkCode.getId() + ".", e);
    } catch (IllegalAccessException e) {
      throw new DotRuntimeException("Unable to load the class for link code id: " + linkCode.getId() + ".", e);
    } catch (IllegalArgumentException e) {
      throw new DotRuntimeException("Unable to load the class for link code id: " + linkCode.getId() + ".", e);
    }
   
    return instance;
  }

  public List<ChainLink> findAllChainLinks() throws DotDataException, DotRuntimeException, DotCacheException {
   
    ArrayList<ChainLink> list = new ArrayList<ChainLink> ();
    List<ChainLinkCode> codes = chainFactory.findAllChainLinkCodes();
   
    for(ChainLinkCode code : codes) {
      ChainLink link =  instanciateChainLink(code.getId());
      list.add(link);
    }
   
    return list;
  }

  public List<Chain> findAllChains() throws DotDataException {
    return chainFactory.findAllChains();
  }

  public ChainLink findChainLinkByClassName(String fullyQualifiedClassName) throws DotDataException, DotRuntimeException, ChainLinkCodeCompilationException, DotCacheException {

    ChainLinkCode code = chainFactory.findChainLinkCodeByClassName(fullyQualifiedClassName);
    if(code == null)
      return null;
    return instanciateChainLink(code);

  }

  public List<ChainLink> findChainLinksByKeyword(String keyword) throws DotRuntimeException, DotDataException, DotCacheException {
    ArrayList<ChainLink> list = new ArrayList<ChainLink> ();
    List<ChainLinkCode> codes = chainFactory.findAllChainLinkCodes();
   
    for(ChainLinkCode code : codes) {
      ChainLink link =  instanciateChainLink(code.getId());
      if(link.getDescription().contains(keyword) || link.getTitle().contains(keyword) ||
          link.getCode().getClassName().contains(keyword))
        list.add(link);
    }
   
    return list;
   
  }

  public List<ChainState> getChainStates(Chain chain) throws DotDataException, DotCacheException {
    return chainFactory.loadChainStates(chain);
  }

  public Chain loadChain(long chainId) throws DotDataException, DotCacheException {
    return chainFactory.loadChain(chainId);
  }

 
  public List<ChainStateParameter> loadChainStateParameters(ChainState chainState) throws DotDataException {
    return chainFactory.findChainStateParameters(chainState);
  }

  protected void deleteChainState (ChainState s) throws DotDataException, DotCacheException {
    List<ChainStateParameter> params = chainFactory.findChainStateParameters(s);
    for(ChainStateParameter param : params) {
      chainFactory.deleteChainStateParameter(param);
    }
    chainFactory.deleteChainState(s);
  }
 
  public void saveChain(Chain chain, List<ChainState> states) throws DotDataException, DotCacheException, DuplicateChainStateParametersException, ChainAlreadyExistsException {

    Chain oldChain = loadChainByKey(chain.getKey());
    if(oldChain != null && oldChain.getId() != chain.getId())
      throw new ChainAlreadyExistsException("A chain with this same key = " + chain.getKey() + " already exists on the sytem.");
   
    //Checking the parameters before save
    List<ChainStateParameter> duplicatedStateParameters = new ArrayList<ChainStateParameter>();
    for(ChainState state : states) {
      Set<String> paramsCheck = new HashSet<String>();
      List<ChainStateParameter> params = state.getParameters();
      for(ChainStateParameter p : params) {
        if(paramsCheck.contains(p.getName()))
          duplicatedStateParameters.add(p);
        paramsCheck.add(p.getName());
      }
     
    }
    if(duplicatedStateParameters.size() > 0)
      throw new DuplicateChainStateParametersException("For your chain: " + chain.getName() + " your are submitting duplicated link parameters",
          duplicatedStateParameters);
   
   
    boolean isNewChain = chain.getId() == 0;
   
    chainFactory.saveChain(chain);
    int order = 1;
   
    //If it's not a new chain state we need to clean up old parameters that might be now deleted
    if(!isNewChain) {
      List<ChainState> oldStates = chainFactory.findChainStates(chain);
      for(ChainState s : oldStates) {
        if(!states.contains(s)) {
          deleteChainState(s);
        }
      }
    }

   
    for(ChainState state : states) {
     
      //Saving chain state
      boolean isNewState = state.getId() == 0;
      state.setOrder(order);
      state.setChainId(chain.getId());
      chainFactory.saveChainState(state);

      //Saving the state parameters
      List<ChainStateParameter> params = state.getParameters();
     
      //If it's not a new chain state we need to clean up old parameters that might be now deleted
      if(!isNewState) {
        List<ChainStateParameter> oldParams = state.getParameters();
        for(ChainStateParameter p : oldParams) {
          if(!params.contains(p))
            chainFactory.deleteChainStateParameter(p);
        }
      }
      for(ChainStateParameter p : params) {
        p.setChainStateId(state.getId());
        chainFactory.saveChainStateParameter(p)
      }

      order++;
    }
   
   
   
  }

  public ChainLink addChainLink(String className, String code, Language lang) throws DuplicatedChainLinkException, DotDataException, DotRuntimeException, ChainLinkCodeCompilationException, DotCacheException {
    return saveChainLink(0, className, code, lang);
  }
 
  public ChainLink saveChainLink(long chainLinkId, String className, String code, Language lang) throws DuplicatedChainLinkException, ChainLinkCodeCompilationException, DotDataException, DotRuntimeException, DotCacheException {

    boolean isNew = false;
    if(chainLinkId == 0)
      isNew = true;
   
    ChainLink oldChainLink = findChainLinkByClassName(className);
    if(oldChainLink != null && isNew)
      throw new DuplicatedChainLinkException ("Another chain link already exist in the system with the same class name.");
    else if (!isNew && oldChainLink.getCode().getId() != chainLinkId)
      throw new DuplicatedChainLinkException ("Another chain link already exist in the system with the same class name.");
   
    ChainLinkCode lcode;
    if(!isNew) {
      lcode = chainFactory.loadChainLinkCode(chainLinkId);
      lcode.setClassName(className);
      lcode.setCode(code);
      lcode.setLanguage(lang);
    } else {
      lcode = new ChainLinkCode (className, code, lang);
    }

   
    ChainLink ret = instanciateChainLink(lcode);
   
    chainFactory.saveChainLinkCode(lcode);
   
    return ret;
  }

  public Chain loadChainByKey(String chainKey) throws DotDataException, DotCacheException {
    return chainFactory.loadChainByKey(chainKey);

  }

  public void deleteChain(Chain chain) throws DotDataException, DotCacheException {
    List<ChainState> states = chainFactory.findChainStates(chain);
    for(ChainState s : states) {
      deleteChainState(s);
    }
    chainFactory.deleteChain(chain);
  }

  public void deleteChainLink(ChainLink chainLink) throws ChainsDependOnCodeException, DotDataException, DotCacheException {
    List<Chain> chains = chainFactory.findDependentChains(chainLink.getCode());
    if(chains.size() > 0)
      throw new ChainsDependOnCodeException(chains);
    chainFactory.deleteChainLinkCode(chainLink.getCode());
  }


}
TOP

Related Classes of com.dotmarketing.portlets.chains.business.ChainAPIImpl$ChainLinkClassLoader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.