All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kuali.maven.plugins.spring.DefaultSpringMojoService Maven / Gradle / Ivy

/**
 * Copyright 2011-2013 The Kuali Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
 *
 * 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 org.kuali.maven.plugins.spring;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.maven.model.Profile;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.StringUtils;
import org.kuali.common.maven.spring.MavenAwareUtils;
import org.kuali.common.util.Assert;
import org.kuali.common.util.CollectionUtils;
import org.kuali.common.util.LongCounter;
import org.kuali.common.util.PropertyUtils;
import org.kuali.common.util.ReflectionUtils;
import org.kuali.common.util.Str;
import org.kuali.common.util.StringFilter;
import org.kuali.common.util.maven.MavenUtils;
import org.kuali.common.util.maven.spring.MavenProfileConstants;
import org.kuali.common.util.property.GlobalPropertiesMode;
import org.kuali.common.util.spring.service.PropertySourceContext;
import org.kuali.common.util.spring.service.PropertySourceService;
import org.kuali.common.util.spring.service.SpringContext;
import org.kuali.common.util.spring.service.SpringService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;

public class DefaultSpringMojoService implements SpringMojoService {

	private static final Logger logger = LoggerFactory.getLogger(DefaultSpringMojoService.class);
	private static final LongCounter SEQUENCE = new LongCounter();

	private final PropertySourceService propertySourceService;

	public DefaultSpringMojoService(PropertySourceService propertySourceService) {
		Assert.noNulls(propertySourceService);
		this.propertySourceService = propertySourceService;
	}

	@Override
	public boolean isDebugLoggingEnabled(AbstractSpringMojo mojo) {
		boolean mojoDebug = mojo.getLog().isDebugEnabled();
		boolean log4JDebug = PropertyUtils.getGlobalBoolean("log4j.debug", mojo.getProperties());
		boolean springDebug = PropertyUtils.getGlobalBoolean("spring.debug", mojo.getProperties());
		return mojoDebug || log4JDebug || springDebug;
	}

	@Override
	public void callback(LoadXmlMojo mojo) {
		LoadContext lc = getLoadContext(mojo);
		if (lc == null) {
			return;
		}

		// Aggregate objects into a SpringContext
		SpringContext context = getSpringContext(mojo, lc.getMavenProperties());

		// Provide some context for looking up property sources
		MavenPropertySourceContext psc = getPropertySourcesContext(mojo, lc);

		// Add the property sources
		addPropertySources(psc, mojo, context);

		logConfiguration(mojo, lc.getMavenProperties(), context.getLocations());

		// Invoke the service to load the context using custom property sources and pre-registered beans
		lc.getService().load(context);
	}

	@Override
	public void callback(LoadMojo mojo) {
		LoadContext lc = getLoadContext(mojo);
		if (lc == null) {
			return;
		}

		// Aggregate objects into a SpringContext
		SpringContext context = getSpringContext(mojo, lc.getMavenProperties());

		// Provide some context for looking up property sources
		MavenPropertySourceContext psc = getPropertySourcesContext(mojo, lc);

		// Add the property sources
		addPropertySources(psc, mojo, context);

		// Show what we are up to
		logConfiguration(mojo, lc.getMavenProperties(), context.getAnnotatedClasses());

		// Invoke the service to load the context using custom property sources and pre-registered beans
		lc.getService().load(context);
	}

	/**
	 * Load the annotated class (or xml file) they provided. Scan it for any beans that implement PropertySource. Any PropertySource beans are sorted
	 * alphabetically by name, and added to the SpringContext
	 */
	protected void addPropertySources(MavenPropertySourceContext ctx, AbstractSpringMojo mojo, SpringContext context) {
		// Are we adding any custom property sources?
		if (mojo.isAddPropertySources()) {
			// Source is either an XML file or an annotated class
			String source = ctx.getLocation() == null ? ctx.getConfig().getName() : ctx.getLocation();
			// Extract PropertySource objects from the Spring application context
			logger.debug("Acquiring custom property sources - [{}]", source);
			List> sources = getPropertySources(ctx);
			String msg = sources.size() == 1 ? "source" : "sources";
			logger.debug("Located {} custom property {}", sources.size(), msg);
			for (PropertySource ps : sources) {
				String name = ps.getName();
				String type = ps.getClass().getName();
				logger.debug("Adding property source - [{}] -> [{}]", name, type);
			}
			// Add them to the SpringContext
			context.setPropertySourceContext(new PropertySourceContext(sources, mojo.isRemoveExistingPropertySources()));
		}

	}

	protected MavenPropertySourceContext getPropertySourcesContext(LoadXmlMojo mojo, LoadContext context) {
		String location = mojo.getPropertySourcesLocation();
		List activeProfiles = getActiveProfiles(mojo);
		List defaultProfiles = getDefaultProfiles(mojo);
		Properties properties = context.getMavenProperties();
		return new MavenPropertySourceContext.Builder(context.getService(), properties).location(location).activeProfiles(activeProfiles).defaultProfiles(defaultProfiles).build();
	}

	protected MavenPropertySourceContext getPropertySourcesContext(LoadMojo mojo, LoadContext context) {
		Class config = ReflectionUtils.getClass(mojo.getPropertySourcesConfig());
		List activeProfiles = getActiveProfiles(mojo);
		List defaultProfiles = getDefaultProfiles(mojo);
		Properties properties = context.getMavenProperties();
		return new MavenPropertySourceContext.Builder(context.getService(), properties).config(config).activeProfiles(activeProfiles).defaultProfiles(defaultProfiles).build();
	}

	protected List> getPropertySources(MavenPropertySourceContext ctx) {
		Map beans = CollectionUtils.toEmptyMap(ctx.getPropertiesBeanName(), (Object) ctx.getProperties());
		if (ctx.getLocation() != null) {
			return propertySourceService.getPropertySources(beans, ctx.getDefaultProfiles(), ctx.getActiveProfiles(), ctx.getLocation());
		} else if (ctx.getConfig() != null) {
			return propertySourceService.getPropertySources(beans, ctx.getDefaultProfiles(), ctx.getActiveProfiles(), ctx.getConfig());
		} else {
			throw new IllegalArgumentException("Must supply either location or an annotated class");
		}
	}

	protected SpringContext getSpringContext(LoadMojo mojo, Properties mavenProperties) {

		// Combine the main annotated class with any optional annotated classes
		List annotatedClassNames = getAnnotatedClassNames(mojo);

		// Convert the strings into actual classes
		List> annotatedClasses = getAnnotatedClasses(annotatedClassNames);

		// These are the beans containing Maven GAV info and (if configured) the Maven model objects
		Map beans = getBeans(mojo, mavenProperties);

		// Accumulate any active Maven profiles into a list
		List activeProfiles = getActiveProfiles(mojo);
		List defaultProfiles = getDefaultProfiles(mojo);

		// Assemble a SpringContext from the information we have
		SpringContext context = new SpringContext();
		context.setDisplayName("Spring Maven Plugin : Load : " + SEQUENCE.increment());
		context.setAnnotatedClasses(annotatedClasses);
		context.setContextBeans(beans);
		context.setActiveProfiles(activeProfiles);
		context.setDefaultProfiles(defaultProfiles);
		return context;
	}

	/**
	 * Return a list of any active Maven profiles + any named profiles provided in the mojo configuration
	 */
	protected List getActiveProfiles(AbstractSpringMojo mojo) {

		// Setup some storage
		List profiles = new ArrayList();

		// Add any active Maven profiles
		List mavenProfiles = mojo.getProject().getActiveProfiles();
		for (Profile profile : CollectionUtils.toEmptyList(mavenProfiles)) {
			String profileId = profile.getId();
			profiles.add(profileId);
		}

		// Add profiles from the plugin config (if any)
		profiles.addAll(CollectionUtils.getTrimmedListFromCSV(mojo.getActiveProfiles()));

		// If we have wired in the Maven properties, activate the profile "autowiredMavenProperties"
		if (mojo.isInjectMavenProperties()) {
			profiles.add(MavenProfileConstants.AUTOWIRED_MAVEN_PROPERTIES);
		}

		// Setup includes / excludes
		List includes = CollectionUtils.getTrimmedListFromCSV(mojo.getActiveProfileIncludes());
		List excludes = CollectionUtils.getNoneSensitiveListFromCSV(mojo.getActiveProfileExcludes());

		// Setup a filter
		StringFilter filter = StringFilter.getInstance(includes, excludes);

		// Filter out profiles that don't belong
		CollectionUtils.filterAndSort(profiles, filter);

		// Return the list
		return profiles;
	}

	/**
	 * Convert the default profiles CSV to a list
	 */
	protected List getDefaultProfiles(AbstractSpringMojo mojo) {
		List profiles = CollectionUtils.getTrimmedListFromCSV(mojo.getDefaultProfiles());

		// Setup includes / excludes
		List includes = CollectionUtils.getTrimmedListFromCSV(mojo.getDefaultProfileIncludes());
		List excludes = CollectionUtils.getNoneSensitiveListFromCSV(mojo.getDefaultProfileExcludes());

		// Setup a filter
		StringFilter filter = StringFilter.getInstance(includes, excludes);

		// Filter out profiles that don't belong
		CollectionUtils.filterAndSort(profiles, filter);

		return profiles;
	}

	protected List getAnnotatedClassNames(LoadMojo mojo) {
		List names = new ArrayList();
		// Add the single annotated class
		if (!StringUtils.isBlank(mojo.getAnnotatedClass())) {
			names.add(mojo.getAnnotatedClass());
		}
		// Add any additional annotated classes
		if (!CollectionUtils.isEmpty(mojo.getAnnotatedClasses())) {
			names.addAll(mojo.getAnnotatedClasses());
		}
		// If nothing has been provided derive a default annotated classname from the project info
		if (names.size() == 0) {
			String name = getDefaultAnnotatedClassname(mojo.getProject());
			names.add(name);
		}
		return names;
	}

	/**
	 * If they supplied an annotated class, use it. Otherwise, use the artifactId to generate a default annotated class name to use.
	 */
	protected String getAnnotatedClassName(LoadMojo mojo) {
		if (!StringUtils.isBlank(mojo.getAnnotatedClass())) {
			return mojo.getAnnotatedClass();
		} else {
			String className = getDefaultAnnotatedClassname(mojo.getProject());
			try {
				Class annotatedClass = ReflectionUtils.getClass(className);
				return annotatedClass.getName();
			} catch (IllegalStateException e) {
				throw new IllegalStateException("No annotated class was provided and the default class [" + className + "] could not be created", e);
			}
		}
	}

	protected List> getAnnotatedClasses(List annotatedClassNames) {
		List> annotatedClasses = new ArrayList>();
		for (String annotatedClassName : annotatedClassNames) {
			Class annotatedClass = ReflectionUtils.getClass(annotatedClassName);
			annotatedClasses.add(annotatedClass);
		}
		return annotatedClasses;
	}

	protected Map getBeans(AbstractSpringMojo mojo, Properties mavenProperties) {
		Map beans = new HashMap();

		if (mojo.isInjectMavenProperties()) {
			beans.put(MavenConstants.DEFAULT_MAVEN_PROPERTIES_BEAN_NAME, mavenProperties);
		}

		if (mojo.isInjectMavenSettings()) {
			beans.put(MavenConstants.DEFAULT_MAVEN_SETTINGS_BEAN_NAME, mojo.getSettings());
		}

		if (mojo.isInjectMavenProject()) {
			beans.put(MavenConstants.DEFAULT_MAVEN_PROJECT_BEAN_NAME, mojo.getProject());
		}

		if (mojo.isInjectMavenMojo()) {
			beans.put(MavenConstants.DEFAULT_MAVEN_MOJO_BEAN_NAME, mojo);
		}

		return beans;
	}

	protected SpringContext getSpringContext(LoadXmlMojo mojo, Properties mavenProperties) {
		// If no location was provided to the mojo, calculate one based on groupId + artifactId
		String location = mojo.getLocation() == null ? getDefaultLocation(mojo.getProject()) : mojo.getLocation();

		// Combine the main context location with any optional locations
		List contextLocations = CollectionUtils.combine(location, mojo.getLocations());

		// These are the beans containing Maven GAV info and (if configured) the Maven model objects
		Map beans = getBeans(mojo, mavenProperties);

		// Accumulate any active Maven profiles into a list (default is one profile named "maven")
		List activeProfiles = getActiveProfiles(mojo);
		List defaultProfiles = getDefaultProfiles(mojo);

		SpringContext context = new SpringContext();
		context.setDisplayName("Spring Maven Plugin : LoadXML : " + SEQUENCE.increment());
		context.setLocations(contextLocations);
		context.setContextBeans(beans);
		context.setActiveProfiles(activeProfiles);
		context.setDefaultProfiles(defaultProfiles);
		return context;
	}

	protected void logConfiguration(AbstractSpringMojo mojo, Properties props, List configurations) {
		logger.debug("---------------- Loading requested Spring configuration ----------------");
		for (Object configuration : configurations) {
			logger.info("Loading - [{}]", configuration);
		}
		if (mojo.isInjectMavenProperties()) {
			logger.debug("Injecting Maven properties - {} total", props.size());
			logger.debug("Displaying " + props.size() + " properties\n\n" + PropertyUtils.toString(props));
		}
		if (mojo.isInjectMavenProject()) {
			logger.debug("Injecting [{}] -> [{}]", MavenConstants.DEFAULT_MAVEN_PROJECT_BEAN_NAME, mojo.getProject().getClass().getName());
		}
		if (mojo.isInjectMavenMojo()) {
			logger.debug("Injecting [{}] -> [{}]", MavenConstants.DEFAULT_MAVEN_MOJO_BEAN_NAME, mojo.getClass().getName());
		}
	}

	protected Properties getMavenProperties(AbstractSpringMojo mojo) {
		MavenProject project = mojo.getProject();
		// Get internal Maven config as a properties object
		Properties internal = MavenAwareUtils.getInternalProperties(project, mojo.getSettings());
		// The ordering here is significant.
		// Properties supplied directly to the mojo override properties from project.getProperties()
		// But, internal Maven properties need to always win.
		// ${project.artifactId} needs to always faithfully represent the correct artifactId
		Properties properties = PropertyUtils.combine(project.getProperties(), project.getProperties(), internal);
		// Explicitly override internal Maven props with system/env props (simulates the default maven behavior)
		PropertyUtils.overrideWithGlobalValues(properties, GlobalPropertiesMode.BOTH);
		// Return the overridden properties
		return properties;
	}

	protected PropertiesPropertySource getMavenPropertySource(AbstractSpringMojo mojo) {
		String name = MavenConstants.DEFAULT_MAVEN_PROPERTIES_BEAN_NAME;
		Properties source = getMavenProperties(mojo);
		return new PropertiesPropertySource(name, source);
	}

	protected String getDefaultLocation(MavenProject project) {
		StringBuilder sb = new StringBuilder();
		sb.append("classpath:");
		sb.append(Str.getPath(project.getGroupId()));
		sb.append("/");
		sb.append("spring");
		sb.append("/");
		sb.append(project.getArtifactId());
		sb.append("-");
		sb.append("context.xml");
		return sb.toString();
	}

	protected String getDefaultAnnotatedClassname(MavenProject project) {
		StringBuilder sb = new StringBuilder();
		sb.append(project.getGroupId());
		sb.append(".");
		sb.append("spring");
		sb.append(".");
		String artifactId = project.getArtifactId();
		String[] tokens = StringUtils.split(artifactId, "-");
		for (String token : tokens) {
			String capitalized = StringUtils.capitalizeFirstLetter(token);
			sb.append(capitalized);
		}
		sb.append("Config");
		return sb.toString();
	}

	protected LoadContext getLoadContext(AbstractSpringMojo mojo) {
		// Might be skipping execution altogether
		if (MavenUtils.skip(mojo.isForceMojoExecution(), mojo.isSkip(), mojo.getProject().getPackaging())) {
			// The MavenUtils.skip() method emits a log message explaining why execution is being skipped
			return null;
		}

		// Combine mojo properties, project properties and internal maven properties into a Properties object
		Properties mavenProperties = getMavenProperties(mojo);

		// Get the desired SpringService implementation
		SpringService service = ReflectionUtils.newInstance(mojo.getSpringService());

		return new LoadContext(mavenProperties, service);
	}

	public PropertySourceService getPropertySourceService() {
		return propertySourceService;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy