Java tutorial
/* * Copyright 2013-2015 Alex Lin and Apache maven-site-plugin project. * * 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 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.opoopress.maven.plugins.plugin; import freemarker.template.utility.StringUtil; import org.apache.commons.lang.ClassUtils; import org.apache.commons.lang.reflect.MethodUtils; import org.apache.maven.artifact.manager.WagonConfigurationException; import org.apache.maven.artifact.manager.WagonManager; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.logging.Log; import org.apache.maven.settings.Profile; import org.apache.maven.settings.Server; import org.apache.maven.settings.Settings; import org.apache.maven.wagon.CommandExecutionException; import org.apache.maven.wagon.CommandExecutor; import org.apache.maven.wagon.ConnectionException; import org.apache.maven.wagon.ResourceDoesNotExistException; import org.apache.maven.wagon.TransferFailedException; import org.apache.maven.wagon.UnsupportedProtocolException; import org.apache.maven.wagon.Wagon; import org.apache.maven.wagon.authentication.AuthenticationException; import org.apache.maven.wagon.authentication.AuthenticationInfo; import org.apache.maven.wagon.authorization.AuthorizationException; import org.apache.maven.wagon.observers.Debug; import org.apache.maven.wagon.proxy.ProxyInfo; import org.apache.maven.wagon.repository.Repository; import org.codehaus.plexus.PlexusConstants; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; import org.codehaus.plexus.component.configurator.ComponentConfigurator; import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.configuration.PlexusConfiguration; import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; import org.codehaus.plexus.context.Context; import org.codehaus.plexus.context.ContextException; import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.opoo.press.impl.ConfigImpl; import org.opoo.press.impl.SiteImpl; import org.opoo.util.ChainingClassLoader; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; /** * @author Alex Lin * @author <a href="mailto:michal@org.codehaus.org">Michal Maczka</a> */ public class AbstractDeployMojo extends AbstractBuildMojo implements Contextualizable { /** * Set this to 'true' to skip deploy. * * @parameter expression="${op.deploy.skip}" default-value="false" */ private boolean skipDeploy; /** * Extra deploy repository configurations. format: <code>id::url[,id::url]</code>. * * @parameter expression="${op.deploy.repos}" */ private String deployRepositories; /** * Whether to run the "chmod" command on the remote site after the deploy. * Defaults to "true". * * @parameter expression="${op.chmod}" default-value="true" * @since 2.1 */ private boolean chmod; /** * The mode used by the "chmod" command. Only used if chmod = true. Defaults * to "g+w,a+rX". * * @parameter expression="${op.chmod.mode}" default-value="g+w,a+rX" * @since 2.1 */ private String chmodMode; /** * The options used by the "chmod" command. Only used if chmod = true. * Defaults to "-Rf". * * @parameter expression="${op.chmod.options}" default-value="-Rf" * @since 2.1 */ private String chmodOptions; /** * @component */ private WagonManager wagonManager; /** * The current user system settings for use in Maven. * * @parameter expression="${settings}" * @required * @readonly */ private Settings settings; private PlexusContainer container; @Override protected void executeInternal(ConfigImpl config) throws MojoExecutionException, MojoFailureException { if (skipDeploy) { getLog().info("Skipping deploy."); return; } showDrafts = false; super.executeInternal(config); } @Override protected void executeInternal(ConfigImpl config, SiteImpl site) throws MojoExecutionException, MojoFailureException { File destination = site.getDestination(); getLog().info("Destination [" + destination + "]"); getLog().info("Site root [" + site.getRoot() + "]"); if (!destination.exists()) { throw new MojoFailureException("The site output folder does not exist, please run mvn op:build first"); } List<Map<String, String>> deployList = getDeployRepositoryList(config); //config.get("deploy"); if (deployList == null || deployList.isEmpty()) { throw new MojoFailureException("Deploy configuration not found in config.yml"); } for (Map<String, String> deployRepo : deployList) { Repository repository = createRepository(deployRepo); deploy(site, destination, repository); } } private List<Map<String, String>> getDeployRepositoryList(ConfigImpl config) { List<Map<String, String>> deployList = config.get("deploy"); if (deployRepositories != null) { String[] split = StringUtil.split(deployRepositories, ','); for (String str : split) { String[] strings = str.split("::"); if (strings.length == 2) { Map<String, String> map = new HashMap<String, String>(); map.put("id", strings[0]); map.put("url", strings[1]); if (deployList == null) { deployList = new ArrayList<Map<String, String>>(); } deployList.add(map); } } } return deployList; } private Repository createRepository(Map<String, String> repo) throws MojoExecutionException, MojoFailureException { String id = repo.get("id"); String url = repo.get("url"); if (id == null || url == null) { throw new MojoFailureException("Deploy configuration must contains 'id' and 'url': " + repo); } url = resolveRepositoryURL(id, url); Properties props = new Properties(); for (String key : repo.keySet()) { if ("id".equals(key) || "url".equals(key)) { continue; } props.setProperty(key, repo.get(key)); } Repository repository = new Repository(id, appendSlash(url)); if (!props.isEmpty()) { repository.setParameters(props); } return repository; } private String resolveRepositoryURL(String repositoryId, String repositoryURL) throws MojoFailureException { //1. starts with '${' and ends with '}' //if(repositoryURL.startsWith("${") && repositoryURL.endsWith("}")){ // return resolveRepositoryURL(repositoryId, repositoryURL.substring(2, repositoryURL.length() - 1)); //} //2. more properties holder if (repositoryURL.contains("${") && repositoryURL.contains("}")) { Set<String> propertyNames = getPropertyNames(repositoryURL); for (String propertyName : propertyNames) { String value = getPropertyValue(propertyName); repositoryURL = repositoryURL.replace("${" + propertyName + "}", value); } } return repositoryURL; } private Set<String> getPropertyNames(String url) throws MojoFailureException { Set<String> set = new HashSet<String>(); int fromIndex = 0; while (true) { int start = url.indexOf("${", fromIndex); if (start == -1) { break; } int end = url.indexOf("}", start + 2); if (end == -1) { throw new MojoFailureException("Invalid deploy repository url: " + url); } fromIndex = end + 2; String prop = url.substring(start + 2, end); set.add(prop); } return set; } private String getPropertyValue(String propertyName) throws MojoFailureException { Map<String, Profile> profiles = settings.getProfilesAsMap(); List<String> activeProfiles = settings.getActiveProfiles(); for (String id : activeProfiles) { Profile profile = profiles.get(id); if (profile != null) { Properties properties = profile.getProperties(); if (properties != null) { String property = properties.getProperty(propertyName); if (property != null) { getLog().info("Resolve deploy repository url: " + propertyName + " => " + property); return property; } } } } for (Profile profile : settings.getProfiles()) { if (profile.getActivation().isActiveByDefault()) { Properties properties = profile.getProperties(); if (properties != null) { String property = properties.getProperty(propertyName); if (property != null) { getLog().info("Resolve deploy repository url: " + propertyName + " => " + property); return property; } } } } throw new MojoFailureException("Can not resolve deploy repository url: " + propertyName); } static String appendSlash(final String url) { if (url.endsWith("/")) { return url; } else { return url + "/"; } } private void deploy(SiteImpl site, File directory, Repository repository) throws MojoExecutionException, MojoFailureException { // TODO: work on moving this into the deployer like the other deploy // methods final Wagon wagon = getWagon(repository, wagonManager); try { configureWagon(wagon, repository.getId(), settings, container, getLog()); } catch (WagonConfigurationException e) { throw new MojoExecutionException("Unable to configure Wagon: '" + repository.getProtocol() + "'", e); } String relativeDir = site.getRoot(); if ("".equals(relativeDir)) { relativeDir = "./"; } else if (relativeDir.startsWith("/")) { relativeDir = relativeDir.substring(1); } try { final ProxyInfo proxyInfo = getProxyInfo(repository, wagonManager); push(directory, repository, wagonManager, wagon, proxyInfo, relativeDir, getLog()); if (chmod) { chmod(wagon, repository, chmodOptions, chmodMode); } } finally { try { wagon.disconnect(); } catch (ConnectionException e) { getLog().error("Error disconnecting wagon - ignored", e); } } } private static void configureScpWagonIfRequired(Wagon wagon, Log log) { log.debug("configureScpWagonIfRequired: " + wagon.getClass().getName()); if (System.console() == null) { log.debug("No System.console(), skip configure Wagon"); return; } ClassLoader parent = Thread.currentThread().getContextClassLoader(); if (parent == null) { parent = AbstractDeployMojo.class.getClassLoader(); } List<ClassLoader> loaders = new ArrayList<ClassLoader>(); loaders.add(wagon.getClass().getClassLoader()); ChainingClassLoader loader = new ChainingClassLoader(parent, loaders); Class<?> scpWagonClass; try { scpWagonClass = ClassUtils.getClass(loader, "org.apache.maven.wagon.providers.ssh.jsch.ScpWagon"); } catch (ClassNotFoundException e) { log.debug( "Class 'org.apache.maven.wagon.providers.ssh.jsch.ScpWagon' not found, skip configure Wagon."); return; } //is ScpWagon if (scpWagonClass.isInstance(wagon)) { try { Class<?> userInfoClass = ClassUtils.getClass(loader, "com.opoopress.maven.plugins.plugin.ssh.SystemConsoleInteractiveUserInfo"); Object userInfo = userInfoClass.newInstance(); MethodUtils.invokeMethod(wagon, "setInteractiveUserInfo", userInfo); log.debug("ScpWagon using SystemConsoleInteractiveUserInfo(Java 6+)."); } catch (ClassNotFoundException e) { log.debug( "Class 'com.opoopress.maven.plugins.plugin.ssh.SystemConsoleInteractiveUserInfo' not found, skip configure Wagon."); } catch (InstantiationException e) { log.debug("Instantiate class exception", e); } catch (IllegalAccessException e) { log.debug(e.getMessage(), e); } catch (NoSuchMethodException e) { log.debug(e.getMessage(), e); } catch (InvocationTargetException e) { log.debug(e.getMessage(), e); } } else { log.debug("Not a ScpWagon."); } } private static Wagon getWagon(final Repository repository, final WagonManager manager) throws MojoExecutionException { final Wagon wagon; try { wagon = manager.getWagon(repository); } catch (UnsupportedProtocolException e) { throw new MojoExecutionException("Unsupported protocol: '" + repository.getProtocol() + "'", e); } catch (WagonConfigurationException e) { throw new MojoExecutionException("Unable to configure Wagon: '" + repository.getProtocol() + "'", e); } if (!wagon.supportsDirectoryCopy()) { throw new MojoExecutionException( "Wagon protocol '" + repository.getProtocol() + "' doesn't support directory copying"); } return wagon; } private static void push(final File inputDirectory, final Repository repository, final WagonManager manager, final Wagon wagon, final ProxyInfo proxyInfo, final String relativeDir, final Log log) throws MojoExecutionException { AuthenticationInfo authenticationInfo = manager.getAuthenticationInfo(repository.getId()); log.debug("authenticationInfo with id '" + repository.getId() + "': " + ((authenticationInfo == null) ? "-" : authenticationInfo.getUserName())); try { Debug debug = new Debug(); wagon.addSessionListener(debug); wagon.addTransferListener(debug); if (proxyInfo != null) { log.debug("connect with proxyInfo"); wagon.connect(repository, authenticationInfo, proxyInfo); } else if (proxyInfo == null && authenticationInfo != null) { log.debug("connect with authenticationInfo and without proxyInfo"); wagon.connect(repository, authenticationInfo); } else { log.debug("connect without authenticationInfo and without proxyInfo"); wagon.connect(repository); } log.info("Pushing " + inputDirectory); // TODO: this also uploads the non-default locales, // is there a way to exclude directories in wagon? log.info(" >>> to " + repository.getUrl() + relativeDir); wagon.putDirectory(inputDirectory, relativeDir); } catch (ResourceDoesNotExistException e) { throw new MojoExecutionException("Error uploading site", e); } catch (TransferFailedException e) { throw new MojoExecutionException("Error uploading site", e); } catch (AuthorizationException e) { throw new MojoExecutionException("Error uploading site", e); } catch (ConnectionException e) { throw new MojoExecutionException("Error uploading site", e); } catch (AuthenticationException e) { throw new MojoExecutionException("Error uploading site", e); } } private static void chmod(final Wagon wagon, final Repository repository, final String chmodOptions, final String chmodMode) throws MojoExecutionException { try { if (wagon instanceof CommandExecutor) { CommandExecutor exec = (CommandExecutor) wagon; exec.executeCommand("chmod " + chmodOptions + " " + chmodMode + " " + repository.getBasedir()); } // else ? silently ignore, FileWagon is not a CommandExecutor! } catch (CommandExecutionException e) { throw new MojoExecutionException("Error uploading site", e); } } /** * Configure the Wagon with the information from serverConfigurationMap ( which comes from settings.xml ) * * @param wagon * @param repositoryId * @param settings * @param container * @param log * @throws WagonConfigurationException * @todo Remove when {@link WagonManager#getWagon(Repository) is available}. It's available in Maven 2.0.5. */ private static void configureWagon(Wagon wagon, String repositoryId, Settings settings, PlexusContainer container, Log log) throws WagonConfigurationException { log.debug(" configureWagon "); //config log configureLog(wagon, log); configureScpWagonIfRequired(wagon, log); // MSITE-25: Make sure that the server settings are inserted for (Server server : settings.getServers()) { String id = server.getId(); log.debug("configureWagon server " + id); if (id != null && id.equals(repositoryId) && (server.getConfiguration() != null)) { final PlexusConfiguration plexusConf = new XmlPlexusConfiguration( (Xpp3Dom) server.getConfiguration()); ComponentConfigurator componentConfigurator = null; try { componentConfigurator = (ComponentConfigurator) container.lookup(ComponentConfigurator.ROLE); componentConfigurator.configureComponent(wagon, plexusConf, container.getContainerRealm()); } catch (final ComponentLookupException e) { throw new WagonConfigurationException(repositoryId, "Unable to lookup wagon configurator." + " Wagon configuration cannot be applied.", e); } catch (ComponentConfigurationException e) { throw new WagonConfigurationException(repositoryId, "Unable to apply wagon configuration.", e); } finally { if (componentConfigurator != null) { try { container.release(componentConfigurator); } catch (ComponentLifecycleException e) { log.error("Problem releasing configurator - ignoring: " + e.getMessage()); } } } } } } /** * @param wagon * @param log */ private static void configureLog(Wagon wagon, Log log) { try { Method method = wagon.getClass().getMethod("setLog", Log.class); method.invoke(wagon, log); log.info("Set log for wagon: " + wagon); } catch (Exception e) { log.debug("Wagon does not supports setLog() method."); } } public static ProxyInfo getProxyInfo(Repository repository, WagonManager wagonManager) { ProxyInfo proxyInfo = wagonManager.getProxy(repository.getProtocol()); if (proxyInfo == null) { return null; } String host = repository.getHost(); String nonProxyHostsAsString = proxyInfo.getNonProxyHosts(); for (String nonProxyHost : StringUtils.split(nonProxyHostsAsString, ",;|")) { if (org.apache.commons.lang.StringUtils.contains(nonProxyHost, "*")) { // Handle wildcard at the end, beginning or middle of the nonProxyHost final int pos = nonProxyHost.indexOf('*'); String nonProxyHostPrefix = nonProxyHost.substring(0, pos); String nonProxyHostSuffix = nonProxyHost.substring(pos + 1); // prefix* if (StringUtils.isNotEmpty(nonProxyHostPrefix) && host.startsWith(nonProxyHostPrefix) && StringUtils.isEmpty(nonProxyHostSuffix)) { return null; } // *suffix if (StringUtils.isEmpty(nonProxyHostPrefix) && StringUtils.isNotEmpty(nonProxyHostSuffix) && host.endsWith(nonProxyHostSuffix)) { return null; } // prefix*suffix if (StringUtils.isNotEmpty(nonProxyHostPrefix) && host.startsWith(nonProxyHostPrefix) && StringUtils.isNotEmpty(nonProxyHostSuffix) && host.endsWith(nonProxyHostSuffix)) { return null; } } else if (host.equals(nonProxyHost)) { return null; } } return proxyInfo; } @Override public void contextualize(Context context) throws ContextException { container = (PlexusContainer) context.get(PlexusConstants.PLEXUS_KEY); } }