/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 *******************************************************************************/ package org.ebayopensource.turmeric.eclipse.codegen.utils; import java.net.URL; import java.util.Map; import java.util.Set; import org.apache.commons.lang.NullArgumentException; import org.apache.commons.lang.StringUtils; import org.ebayopensource.turmeric.eclipse.codegen.model.IMultiCodeGenModel; import org.ebayopensource.turmeric.eclipse.codegen.model.IMultiCodeGenModel.IMultiCodeGenModelIterator; import org.ebayopensource.turmeric.eclipse.core.logging.SOALogger; import org.ebayopensource.turmeric.eclipse.repositorysystem.core.GlobalRepositorySystem; import org.ebayopensource.turmeric.eclipse.repositorysystem.model.BaseCodeGenModel; import org.ebayopensource.turmeric.eclipse.utils.classloader.SOAPluginClassLoader; import org.ebayopensource.turmeric.eclipse.utils.collections.MapUtil; import org.ebayopensource.turmeric.eclipse.utils.plugin.JDTUtil; import org.eclipse.core.resources.IProject; /** * This is the main class involved in code generation and can be thought of as * the heart of code generation. Interfaces plugin with SOA tools code * generation. This touch point resolves the class path, sets the class loader * and finally calls the code generation engine. Also expose the class loader * for clients to manipulate the properties if required. * * @author smathew * */ public class CodegenInvoker { private SOAPluginClassLoader soaPluginClassLoader; private static final SOALogger logger = SOALogger.getLogger(); /** * No one should ideally need an interface */ private CodegenInvoker() { } /** * Initializes this invoker, Sets the class path and make the stage ready * for code generation. The key here is the class loader which is loaded * with all the class path required. Also we don't use the the standard IBM * or SUN java class loader, reason being those class loaders seem to be * using a locked stream for reading the classes from a jar file and the * custom class loader address this issue. * * @param project the project * @return the codegen invoker * @throws Exception the exception */ public static CodegenInvoker init(IProject project) throws Exception { if (project == null) { throw new NullArgumentException("Project can not be null"); } Set<URL> urls = JDTUtil.resolveClasspathToURLs(project); SOAPluginClassLoader classLoader = new SOAPluginClassLoader("Codegen", urls.toArray(new URL[0])); CodegenInvoker codegenInvoker = new CodegenInvoker(); codegenInvoker.setSoaPluginClassLoader(classLoader); return codegenInvoker; } /** * Executes the given code generation model in the context created by the. * * @param model - This model has all the parameters required for codegen * invocation. * @return true, if successful * @throws Exception the exception * @see CodegenInvoker#init(IProject). * * This is again a tricky method. We want to have our old class loader * stored temporarily and use the fresh soa class loader for code * generation for obvious reasons( the relevant class path is there in * this class loader). After codegen we will set the old classpath * back. */ public boolean execute(BaseCodeGenModel model) throws Exception { Map<String, String> paramMap = model.getCodeGenOptions(); ClassLoader oldClassLoader = Thread.currentThread() .getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( getSoaPluginClassLoader()); if (model instanceof IMultiCodeGenModel) { for (IMultiCodeGenModelIterator iterator = ((IMultiCodeGenModel) model) .iterator(); iterator.hasNext();) { paramMap = iterator.nextInputOptions(); addJdkHomeOptions(paramMap); logger.info(BaseCodeGenModel.toString(model.getGenType(), paramMap)); callCodegen(MapUtil.toArray(paramMap, new String[0], true)); } } else { addJdkHomeOptions(paramMap); logger.info(BaseCodeGenModel.toString(model.getGenType(), paramMap)); callCodegen(MapUtil.toArray(paramMap, new String[0], true)); } } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } return true; } private static void callCodegen(String[] parameters) throws Exception { if(SOALogger.DEBUG){ logger.debug((Object[])parameters); } GlobalRepositorySystem.instanceOf().getActiveRepositorySystem() .getSOACodegenProvider().generateCode(parameters); } private void addJdkHomeOptions(Map<String, String> paramMap) { final String javaHome = CodeGenUtil.getJavaHome(); if (StringUtils.isNotBlank(javaHome)) paramMap.put(BaseCodeGenModel.PARAM_JAVA_HOME, javaHome); final String jdkHome = CodeGenUtil.getJdkHome(); if (StringUtils.isNotBlank(jdkHome)) paramMap.put(BaseCodeGenModel.PARAM_JDK_HOME, jdkHome); } /** * Usual getter. * * @return the soa plugin class loader */ public SOAPluginClassLoader getSoaPluginClassLoader() { return soaPluginClassLoader; } private void setSoaPluginClassLoader( SOAPluginClassLoader soaPluginClassLoader) { this.soaPluginClassLoader = soaPluginClassLoader; } }