1 package org.apache.rat.analysis;
2 /*
3 * Licensed to the Apache Software Foundation (ASF) under one *
4 * or more contributor license agreements. See the NOTICE file *
5 * distributed with this work for additional information *
6 * regarding copyright ownership. The ASF licenses this file *
7 * to you under the Apache License, Version 2.0 (the *
8 * "License"); you may not use this file except in compliance *
9 * with the License. You may obtain a copy of the License at *
10 * *
11 * http://www.apache.org/licenses/LICENSE-2.0 *
12 * *
13 * Unless required by applicable law or agreed to in writing, *
14 * software distributed under the License is distributed on an *
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
16 * KIND, either express or implied. See the License for the *
17 * specific language governing permissions and limitations *
18 * under the License. *
19 */
20
21 import java.io.BufferedReader;
22 import java.io.IOException;
23 import java.io.Reader;
24 import java.util.Objects;
25
26 import org.apache.rat.ConfigurationException;
27 import org.apache.rat.api.Document;
28 import org.apache.rat.api.MetaData;
29 import org.apache.rat.license.ILicense;
30
31 /**
32 * Reads from a stream to check license.
33 * <p>
34 * <strong>Note</strong> that this class is not thread safe.
35 * </p>
36 */
37 class HeaderCheckWorker {
38
39 /* TODO revisit this class. It is only used in one place and can be moved inline as the DocumentHeaderAnalyser states.
40 * However, it may also be possible to make the entire set threadsafe so that multiple files can be checked simultaneously.
41 */
42 /**
43 * The default number of header lines to read while looking for the license
44 * information.
45 */
46 public static final int DEFAULT_NUMBER_OF_RETAINED_HEADER_LINES = 50;
47
48 private final int numberOfRetainedHeaderLines;
49 private final BufferedReader reader;
50 private final ILicense license;
51 private final Document document;
52
53 private int headerLinesToRead;
54 private boolean finished = false;
55
56 /**
57 * Convenience constructor wraps given <code>Reader</code> in a
58 * <code>BufferedReader</code>.
59 *
60 * @param reader The reader on the document. not null.
61 * @param license The license to check against. not null.
62 * @param name The document that is being checked. possibly null
63 */
64 public HeaderCheckWorker(Reader reader, final ILicense license, final Document name) {
65 this(reader, DEFAULT_NUMBER_OF_RETAINED_HEADER_LINES, license, name);
66 }
67
68 /**
69 * Constructs a check worker for the license against the specified document.
70 *
71 * @param reader The reader on the document. not null.
72 * @param numberOfRetainedHeaderLine the maximum number of lines to read to find
73 * the license information.
74 * @param license The license to check against. not null.
75 * @param name The document that is being checked. possibly null
76 */
77 public HeaderCheckWorker(Reader reader, int numberOfRetainedHeaderLine, final ILicense license,
78 final Document name) {
79 Objects.requireNonNull(reader, "Reader may not be null");
80 Objects.requireNonNull(license, "License may not be null");
81 if (numberOfRetainedHeaderLine < 0) {
82 throw new ConfigurationException("numberOfRetainedHeaderLine may not be less than zero");
83 }
84 this.reader = reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader);
85 this.numberOfRetainedHeaderLines = numberOfRetainedHeaderLine;
86 this.license = license;
87 this.document = name;
88 }
89
90 /**
91 * @return {@code true} if the header check is complete.
92 */
93 public boolean isFinished() {
94 return finished;
95 }
96
97 /**
98 * Read the input and perform the header check.
99 *
100 * @throws RatHeaderAnalysisException on IO Exception.
101 */
102 public void read() throws RatHeaderAnalysisException {
103 if (!finished) {
104 final StringBuilder headers = new StringBuilder();
105 headerLinesToRead = numberOfRetainedHeaderLines;
106 try {
107 while (readLine(headers)) {
108 // do nothing
109 }
110 if (license.finalizeState().asBoolean()) {
111 document.getMetaData().reportOnLicense(license);
112 } else {
113 document.getMetaData().reportOnLicense(UnknownLicense.INSTANCE);
114 document.getMetaData().set(new MetaData.Datum(MetaData.RAT_URL_HEADER_SAMPLE, headers.toString()));
115 }
116 } catch (IOException e) {
117 throw new RatHeaderAnalysisException("Cannot read header for " + document, e);
118 }
119 license.reset();
120 }
121 finished = true;
122 }
123
124 boolean readLine(StringBuilder headers) throws IOException {
125 String line = reader.readLine();
126 boolean result = line != null;
127 if (result) {
128 if (headerLinesToRead-- > 0) {
129 headers.append(line);
130 headers.append('\n');
131 }
132 switch (license.matches(line)) {
133 case t:
134 result = false;
135 break;
136 case f:
137 case i:
138 result = true;
139 break;
140 }
141 }
142 return result;
143 }
144 }