View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.internal.transformation;
20  
21  import java.io.IOException;
22  import java.io.UncheckedIOException;
23  import java.nio.file.Files;
24  import java.nio.file.Path;
25  import java.util.Objects;
26  import java.util.concurrent.atomic.AtomicReference;
27  import java.util.function.BiConsumer;
28  import java.util.function.Function;
29  import java.util.function.Supplier;
30  
31  import static java.util.Objects.requireNonNull;
32  
33  /**
34   * Keeps transformed file up-to-date relative to its source file. It manages state (i.e. hashing the content) using
35   * passed in stateFunction, and transforms when needed using passed in transformer bi-consumer.
36   * <p>
37   * Covered cases:
38   * <ul>
39   *     <li>when source supplier returns {@code null}, this class will return {@code null}.</li>
40   *     <li>when source supplier returns non existing path, this class will return non existing path.</li>
41   *     <li>when source supplier returns existing path, this class will ensure transformation is in sync.</li>
42   * </ul>
43   *
44   * @since TBD
45   */
46  final class OnChangeTransformer implements Supplier<Path> {
47  
48      private final Supplier<Path> source;
49  
50      private final Path target;
51  
52      private final Function<Path, String> stateFunction;
53  
54      private final BiConsumer<Path, Path> transformerConsumer;
55  
56      private final AtomicReference<String> sourceState;
57  
58      OnChangeTransformer(
59              Supplier<Path> source,
60              Path target,
61              Function<Path, String> stateFunction,
62              BiConsumer<Path, Path> transformerConsumer) {
63          this.source = requireNonNull(source);
64          this.target = requireNonNull(target);
65          this.stateFunction = requireNonNull(stateFunction);
66          this.transformerConsumer = requireNonNull(transformerConsumer);
67          this.sourceState = new AtomicReference<>(null);
68      }
69  
70      @Override
71      public synchronized Path get() {
72          String state = mayUpdate();
73          if (state == null) {
74              return null;
75          }
76          return target;
77      }
78  
79      private String mayUpdate() {
80          String result;
81          try {
82              Path src = source.get();
83              if (src == null) {
84                  Files.deleteIfExists(target);
85                  result = null;
86              } else if (!Files.exists(src)) {
87                  Files.deleteIfExists(target);
88                  result = "";
89              } else {
90                  String current = stateFunction.apply(src);
91                  String existing = sourceState.get();
92                  if (!Objects.equals(current, existing)) {
93                      transformerConsumer.accept(src, target);
94                      Files.setLastModifiedTime(target, Files.getLastModifiedTime(src));
95                  }
96                  result = current;
97              }
98          } catch (IOException e) {
99              throw new UncheckedIOException(e);
100         }
101         sourceState.set(result);
102         return result;
103     }
104 }