001    /*
002     * Copyright (C) 2006-2007 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.codehaus.gmaven.plugin.execute;
018    
019    import org.apache.maven.execution.MavenSession;
020    import org.apache.maven.project.MavenProject;
021    import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
022    import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
023    import org.slf4j.Logger;
024    import org.slf4j.LoggerFactory;
025    
026    import java.util.ArrayList;
027    import java.util.Collections;
028    import java.util.Iterator;
029    import java.util.List;
030    import java.util.Map;
031    import java.util.Properties;
032    
033    /**
034     * Provides property resolution access to Groovy executions.
035     *
036     * @version $Id: GroovyMavenProjectAdapter.java 110 2010-08-06 19:46:53Z user57 $
037     * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
038     */
039    public class GroovyMavenProjectAdapter
040        extends MavenProjectDelegateAdapter
041    {
042        private final MavenSession session;
043    
044        private final Map properties;
045    
046        private final Map defaults;
047        
048        private Properties props;
049    
050        public GroovyMavenProjectAdapter(final MavenProject project, final MavenSession session, final Map properties, final Map defaults) {
051            super(project);
052    
053            this.session = session;
054            this.properties = properties;
055            this.defaults = defaults;
056        }
057    
058        public synchronized Properties getProperties() {
059            // Lazily construct a custom properties class to handle resolving properties as we want them
060            if (props == null) {
061                props = new EvaluatingProperties();
062            }
063    
064            return props;
065        }
066    
067        /**
068         * Custom properties handling to resolve for Groovy executions.
069         */
070        private class EvaluatingProperties
071            extends Properties
072        {
073            private final Logger log = LoggerFactory.getLogger(getClass());
074    
075            private final ExpressionEvaluator evaluator = new ExpressionEvaluatorImpl(session, GroovyMavenProjectAdapter.this);
076    
077            public EvaluatingProperties() {
078                // Populate the base properties from the original model properties (so iter-based operations work as expected)
079                putAll(getModel().getProperties());
080    
081                // Add custom execution properties
082                if (properties != null) {
083                    putAll(properties);
084                }
085    
086                if (log.isDebugEnabled() && props != null && !props.isEmpty()) {
087                    log.debug("Properties: ");
088    
089                    List keys = new ArrayList();
090                    keys.addAll(props.keySet());
091    
092                    Collections.sort(keys);
093    
094                    for (Iterator iter = keys.iterator(); iter.hasNext();) {
095                        String name = (String)iter.next();
096                        String value = props.getProperty(name);
097    
098                        log.debug("    {} -> {}", name, value);
099                    }
100                }
101            }
102    
103            //
104            // NOTE: lookup() and get() are marked as public intentionally... as they could be potentially useful by some
105            //       advanced scripts which need richer access to properties.  Though, I think Groovy's reflector muck
106            //       can actually invoke the privates just as well.
107            //
108    
109            public Object lookup(final Object key) {
110                // First try execution properties, should include system
111                Object value = session.getExecutionProperties().get(key);
112    
113                // Else try ourselves
114                if (value == null) {
115                    value = super.get(key);
116                }
117    
118                // Then try defaults (from adapter, not from properties, which is not used)
119                if (value == null && GroovyMavenProjectAdapter.this.defaults != null) {
120                    value = GroovyMavenProjectAdapter.this.defaults.get(key);
121                }
122    
123                return value;
124            }
125    
126            public Object get(final Object key, final boolean resolve) {
127                Object value = lookup(key);
128    
129                // If the value is a string, evaluate it to get expressions to expand
130                if (resolve && value instanceof String) {
131                    try {
132                        value = evaluator.evaluate((String)value);
133                    }
134                    catch (ExpressionEvaluationException e) {
135                        // If something bad happens just puke it up
136                        throw new RuntimeException(e);
137                    }
138                }
139    
140                log.trace("Getting value: {} = {}", key, value);
141    
142                return value;
143            }
144    
145            public Object get(final Object key) {
146                return get(key, true);
147            }
148    
149            public String getProperty(final String name) {
150                // We have to override getProperty() as the default impl gets the value from super.get() instead of get()
151                Object value = get(name);
152    
153                log.trace("Getting property: {} = {}", name, value);
154    
155                return value != null ? String.valueOf(value) : null;
156            }
157    
158            public Object put(final Object key, final Object value) {
159                log.trace("Putting value: {} = {}", key, value);
160    
161                // Have to set in the original to preserve between executions
162                getDelegate().getProperties().put(key, value);
163    
164                // But need to update our self so resolution in the same execution works too
165                return super.put(key, value);
166            }
167        }
168    }