blob: 486bbcf9be9058286bf273ce86d97554de34c0ba [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache 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.apache.org/licenses/LICENSE-2.0
*
* 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.apache.creadur.whisker.app.analysis;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.creadur.whisker.model.Resource;
import org.apache.creadur.whisker.model.ResourceNamesCollator;
import org.apache.creadur.whisker.model.Descriptor;
import org.apache.creadur.whisker.scan.Directory;
/**
* Analyses licenses.
*/
public class LicenseAnalyst {
/**
* Maps issues.
* @return not null
*/
private static Map<ResourceDefinitionError,
Collection<ResourceDescription>> buildIssueMap() {
final Map<ResourceDefinitionError,
Collection<ResourceDescription>> results =
new HashMap<ResourceDefinitionError,
Collection<ResourceDescription>>();
for (final ResourceDefinitionError error:
ResourceDefinitionError.values()) {
initIssues(results, error);
}
return results;
}
/**
* Builds an initial map.
* @param results not null
* @param error not null
*/
private static void initIssues(
final Map<
ResourceDefinitionError,
Collection<ResourceDescription>> results,
ResourceDefinitionError error) {
results.put(error, new TreeSet<ResourceDescription>());
}
/** Directories analysed. */
private final Collection<Directory> directories;
/** Maps resource errors to resources. */
private final Map<ResourceDefinitionError,
Collection<ResourceDescription>> issues;
/**
* Constructs empty analyst.
*/
public LicenseAnalyst() {
this(null);
}
/**
* Analyse the given directories.
* @param directories not null
*/
public LicenseAnalyst(final Collection<Directory> directories) {
super();
this.directories = directories;
issues = buildIssueMap();
}
/**
* Discover discrepancies between meta-data and source directories.
* @param work not null
* @return this, not null
*/
public LicenseAnalyst analyse(final Descriptor work) {
if (directories == null) {
final ResourceNamesCollator collator =
new ResourceNamesCollator();
work.traverse(collator);
analyseDuplicates(collator);
final ResourceSourceAuditor sourceAuditor =
new ResourceSourceAuditor();
work.traverse(sourceAuditor);
analyse(sourceAuditor);
} else {
for (final Directory directory: directories) {
final ResourceNamesCollator collator =
new ResourceNamesCollator();
work.traverseDirectory(collator, directory.getName());
analyseLicenses(directory, collator);
analyseDuplicates(collator);
final ResourceSourceAuditor sourceAuditor = new
ResourceSourceAuditor();
work.traverseDirectory(sourceAuditor, directory.getName());
analyse(sourceAuditor);
}
}
return this;
}
/**
* Analyse the directories with this auditor.
* @param sourceAuditor not null
*/
private void analyse(final ResourceSourceAuditor sourceAuditor) {
addIssues(sourceAuditor.getResourcesMissingSource(),
ResourceDefinitionError.MISSING_SOURCE);
}
/**
* Were any errors found?
* @return true when the meta-data is valid,
* false otherwise
*/
public boolean isValid() {
for (final ResourceDefinitionError error:
ResourceDefinitionError.values()) {
if (!getIssues(error).isEmpty()) {
return false;
}
}
return true;
}
/**
* Checks the descriptor against the source directories.
* @param work not null
* @return valid meta-data
* @throws ResourceDefinitionException when issues are found
*/
public Descriptor validate(final Descriptor work)
throws ResourceDefinitionException {
analyse(work);
if (isValid()) {
return work;
} else {
throw new ResourceDefinitionException(issues);
}
}
/**
* Discovers duplicates.
* @param collator not null
*/
private void analyseDuplicates(
final ResourceNamesCollator collator) {
addIssues(collator.getDuplicates(),
ResourceDefinitionError.DUPLICATE);
}
/**
* Adds the issues to the store.
* @param resources not null
* @param error not null
*/
private void addIssues(
final Collection<Pair<
org.apache.creadur.whisker.model.WithinDirectory,
Resource>> resources,
final ResourceDefinitionError error) {
for (Pair<
org.apache.creadur.whisker.model.WithinDirectory,
Resource> duplicate: resources) {
getIssues(error).add(
new ResourceDescription(
duplicate.getLeft().getName(),
duplicate.getRight().getName()));
}
}
/**
* Checks for too many or few licenses.
* @param directory not null
* @param collator not null
*/
private void analyseLicenses(final Directory directory,
final ResourceNamesCollator collator) {
analyseExtraLicenses(directory, collator);
analyseMissingLicenses(directory, collator);
}
/**
* Checks for to many licenses.
* @param directory not null
* @param collator not null
*/
private void analyseExtraLicenses(final Directory directory,
final ResourceNamesCollator collator) {
final Collection<String> actualResources = directory.getContents();
for (final String resourceLicense: collator.getNames()) {
if (!actualResources.contains(resourceLicense)) {
getExtraLicenses().add(
new ResourceDescription(
directory.getName(),
resourceLicense));
}
}
}
/**
* Checks for too few licenses.
* @param directory not null
* @param collator not null
*/
private void analyseMissingLicenses(final Directory directory,
final ResourceNamesCollator collator) {
final Collection<String> licensedResources = collator.getNames();
for (final String actualResource: directory.getContents()) {
if (!licensedResources.contains(actualResource)) {
getMissingLicenses().add(
new ResourceDescription(
directory.getName(),
actualResource));
}
}
}
/**
* Gets resources whose sources are missing.
* @return not null, possibly empty
*/
public Collection<ResourceDescription> getResourcesMissingSources() {
return getIssues(ResourceDefinitionError.MISSING_SOURCE);
}
/**
* Gets surplus licenses.
* @return not null, possibly empty
*/
public Collection<ResourceDescription> getExtraLicenses() {
return getIssues(ResourceDefinitionError.EXTRA_LICENSE);
}
/**
* Gets missing license.
* @return not null, possibly empty
*/
public Collection<ResourceDescription> getMissingLicenses() {
return getIssues(ResourceDefinitionError.MISSING_LICENSE);
}
/**
* Gets duplicate resources.
* @return the duplicates
*/
public Collection<ResourceDescription> getDuplicates() {
return getIssues(ResourceDefinitionError.DUPLICATE);
}
/**
* Gets issues by type.
* @param ofType not null
* @return issues of given type, not null, possibly empty
*/
public Collection<ResourceDescription> getIssues(
ResourceDefinitionError ofType) {
return issues.get(ofType);
}
/**
* Describes suitably for logging.
* @return something suitable for logging
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "LicenseAnalyst [directories=" + directories + "]";
}
}