View Javadoc
1   /*
2   Copyright (c) 2008 Sonatype, Inc. All rights reserved.
3   
4   This program is licensed to you under the Apache License Version 2.0,
5   and you may not use this file except in compliance with the Apache License Version 2.0.
6   You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
7   
8   Unless required by applicable law or agreed to in writing,
9   software distributed under the Apache License Version 2.0 is distributed on an
10  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
12  */
13  
14  package org.codehaus.plexus.build;
15  
16  import javax.inject.Inject;
17  import javax.inject.Named;
18  import javax.inject.Singleton;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.OutputStream;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.concurrent.ConcurrentHashMap;
26  
27  import org.apache.maven.plugin.LegacySupport;
28  import org.codehaus.plexus.build.connect.BuildConnection;
29  import org.codehaus.plexus.build.connect.messages.RefreshMessage;
30  import org.codehaus.plexus.logging.AbstractLogEnabled;
31  import org.codehaus.plexus.util.Scanner;
32  import org.codehaus.plexus.util.io.CachingOutputStream;
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  /**
37   * Filesystem based non-incremental build context implementation which behaves
38   * as if all files were just created. More specifically,
39   *
40   * <ol>
41   * <li>hasDelta returns <code>true</code> for all paths</li>
42   * <li>newScanner returns Scanner that scans all files under provided
43   * basedir</li>
44   * <li>newDeletedScanner always returns empty scanner</li>
45   * <li>isIncremental returns <code>false</code></li>
46   * <li>getValue always returns the last set value in this session and only
47   * stores to memory</li>
48   * </ol>
49   */
50  @Named("default")
51  @Singleton
52  public class DefaultBuildContext implements BuildContext {
53  
54      private final Logger logger = LoggerFactory.getLogger(DefaultBuildContext.class);
55      // the legacy API requires the AbstractLogEnabled we just have it here to get
56      // compile errors in case it is missing from the classpath!
57      @SuppressWarnings("unused")
58      private static final AbstractLogEnabled DUMMY = null;
59  
60      private final Map<String, Object> contextMap = new ConcurrentHashMap<>();
61      private org.sonatype.plexus.build.incremental.BuildContext legacy;
62      private BuildConnection connection;
63      private LegacySupport legacySupport;
64  
65      /**
66       * @param legacy        the legacy API we delegate to by default, this allow us
67       *                      to support "older" plugins and implementors of the API
68       *                      while still having a way to move forward!
69       * @param connection    the connection we use to forward refresh events
70       * @param legacySupport legacy support to get the current session
71       */
72      @Inject
73      public DefaultBuildContext(
74              org.sonatype.plexus.build.incremental.BuildContext legacy,
75              BuildConnection connection,
76              LegacySupport legacySupport) {
77          this.legacy = legacy;
78          this.connection = connection;
79          this.legacySupport = legacySupport;
80      }
81  
82      /** {@inheritDoc} */
83      public boolean hasDelta(String relpath) {
84          return legacy.hasDelta(relpath);
85      }
86  
87      /**
88       * <p>hasDelta.</p>
89       *
90       * @param file a {@link java.io.File} object.
91       * @return a boolean.
92       */
93      public boolean hasDelta(File file) {
94          return legacy.hasDelta(file);
95      }
96  
97      /**
98       * <p>hasDelta.</p>
99       *
100      * @param relpaths a {@link java.util.List} object.
101      * @return a boolean.
102      */
103     public boolean hasDelta(List<String> relpaths) {
104         return legacy.hasDelta(relpaths);
105     }
106 
107     /** {@inheritDoc} */
108     public OutputStream newFileOutputStream(File file) throws IOException {
109         if (isDefaultImplementation()) {
110             return new CachingOutputStream(file.toPath());
111         }
112         return legacy.newFileOutputStream(file);
113     }
114 
115     /**
116      * @return <code>true</code> if the legacy is the default implementation and we
117      *         can safely override/change behavior here, or <code>false</code> if a
118      *         custom implementation is used and full delegation is required.
119      */
120     private boolean isDefaultImplementation() {
121         return legacy.getClass().equals(org.sonatype.plexus.build.incremental.DefaultBuildContext.class);
122     }
123 
124     /** {@inheritDoc} */
125     public Scanner newScanner(File basedir) {
126         return legacy.newScanner(basedir);
127     }
128 
129     /** {@inheritDoc} */
130     public void refresh(File file) {
131         legacy.refresh(file);
132         connection.send(new RefreshMessage(file.toPath()), legacySupport.getSession());
133     }
134 
135     /** {@inheritDoc} */
136     public Scanner newDeleteScanner(File basedir) {
137         return legacy.newDeleteScanner(basedir);
138     }
139 
140     /** {@inheritDoc} */
141     public Scanner newScanner(File basedir, boolean ignoreDelta) {
142         return legacy.newScanner(basedir, ignoreDelta);
143     }
144 
145     /**
146      * <p>isIncremental.</p>
147      *
148      * @return a boolean.
149      */
150     public boolean isIncremental() {
151         return legacy.isIncremental();
152     }
153 
154     /** {@inheritDoc} */
155     public Object getValue(String key) {
156         if (isDefaultImplementation()) {
157             return contextMap.get(key);
158         }
159         return legacy.getValue(key);
160     }
161 
162     /** {@inheritDoc} */
163     public void setValue(String key, Object value) {
164         if (isDefaultImplementation()) {
165             contextMap.put(key, value);
166         }
167         legacy.setValue(key, value);
168     }
169 
170     /** {@inheritDoc} */
171     public void addError(File file, int line, int column, String message, Throwable cause) {
172         addMessage(file, line, column, message, SEVERITY_ERROR, cause);
173     }
174 
175     /** {@inheritDoc} */
176     public void addWarning(File file, int line, int column, String message, Throwable cause) {
177         addMessage(file, line, column, message, SEVERITY_WARNING, cause);
178     }
179 
180     private String getMessage(File file, int line, int column, String message) {
181         return file.getAbsolutePath() + " [" + line + ':' + column + "]: " + message;
182     }
183 
184     /** {@inheritDoc} */
185     public void addMessage(File file, int line, int column, String message, int severity, Throwable cause) {
186         if (isDefaultImplementation()) {
187             switch (severity) {
188                 case BuildContext.SEVERITY_ERROR:
189                     logger.error(getMessage(file, line, column, message), cause);
190                     return;
191                 case BuildContext.SEVERITY_WARNING:
192                     logger.warn(getMessage(file, line, column, message), cause);
193                     return;
194                 default:
195                     logger.debug(getMessage(file, line, column, message), cause);
196                     return;
197             }
198         }
199         legacy.addMessage(file, line, column, message, severity, cause);
200     }
201 
202     /** {@inheritDoc} */
203     public void removeMessages(File file) {
204         if (isDefaultImplementation()) {
205             return;
206         }
207         legacy.removeMessages(file);
208     }
209 
210     /** {@inheritDoc} */
211     public boolean isUptodate(File target, File source) {
212         return legacy.isUptodate(target, source);
213     }
214 }