Skip to content

Commit

Permalink
feat(project): Reporting Improvements
Browse files Browse the repository at this point in the history
This pull request adds:

- Reporting: Add to License Report List of 3rd Party Components eclipse-sw360#375
- Reporting: License report new structure: cover page eclipse-sw360#377
- Reporting: License report new proposed structure: Sections eclipse-sw360#378
- Reporting: License Report: Add Fixed Template Text eclipse-sw360#379
- Reporting: License Report: Add Editable Default Texts eclipse-sw360#380

closes eclipse-sw360#375
closes eclipse-sw360#377
closes eclipse-sw360#378
closes eclipse-sw360#379
closes eclipse-sw360#380

Signed-off-by: Johannes Amorosa <johannes.amorosa@endocode.com>
  • Loading branch information
Johannes Amorosa committed Dec 4, 2018
1 parent db60f4b commit 8d62965
Show file tree
Hide file tree
Showing 29 changed files with 803 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
import org.eclipse.sw360.datahandler.db.ComponentDatabaseHandler;
import org.eclipse.sw360.datahandler.thrift.attachments.Attachment;
import org.eclipse.sw360.datahandler.thrift.components.Release;
import org.eclipse.sw360.datahandler.thrift.ThriftClients;
import org.eclipse.sw360.datahandler.thrift.components.ComponentService;
import org.eclipse.sw360.datahandler.thrift.components.Component;
import org.eclipse.sw360.datahandler.thrift.components.ComponentType;
import org.eclipse.sw360.datahandler.thrift.licenseinfo.*;
import org.eclipse.sw360.datahandler.thrift.projects.Project;
import org.eclipse.sw360.datahandler.thrift.users.User;
Expand All @@ -52,14 +56,17 @@ public class LicenseInfoHandler implements LicenseInfoService.Iface {
private static final Logger LOGGER = Logger.getLogger(LicenseInfoHandler.class);
private static final int CACHE_TIMEOUT_MINUTES = 15;
private static final int CACHE_MAX_ITEMS = 100;
private static final String DEFAULT_LICENSE_INFO_HEADER_FILE="/DefaultLicenseInfoHeader.txt";
private static final String DEFAULT_LICENSE_INFO_TEXT = loadDefaultLicenseInfoHeaderText();
private static final String DEFAULT_LICENSE_INFO_HEADER_FILE = "/DefaultLicenseInfoHeader.txt";
private static final String DEFAULT_LICENSE_INFO_TEXT = dropCommentedLine(DEFAULT_LICENSE_INFO_HEADER_FILE);
private static final String DEFAULT_OBLIGATIONS_FILE = "/DefaultObligations.txt";
private static final String DEFAULT_OBLIGATIONS_TEXT = dropCommentedLine(DEFAULT_OBLIGATIONS_FILE);
public static final String MSG_NO_RELEASE_GIVEN = "No release given";

protected List<LicenseInfoParser> parsers;
protected List<OutputGenerator<?>> outputGenerators;
protected ComponentDatabaseHandler componentDatabaseHandler;
protected Cache<String, List<LicenseInfoParsingResult>> licenseInfoCache;
protected Cache<String, List<ObligationParsingResult>> obligationCache;

public LicenseInfoHandler() throws MalformedURLException {
this(new AttachmentDatabaseHandler(DatabaseSettings.getConfiguredHttpClient(), DatabaseSettings.COUCH_DB_DATABASE, DatabaseSettings.COUCH_DB_ATTACHMENTS),
Expand All @@ -72,6 +79,8 @@ protected LicenseInfoHandler(AttachmentDatabaseHandler attachmentDatabaseHandler
this.componentDatabaseHandler = componentDatabaseHandler;
this.licenseInfoCache = CacheBuilder.newBuilder().expireAfterWrite(CACHE_TIMEOUT_MINUTES, TimeUnit.MINUTES)
.maximumSize(CACHE_MAX_ITEMS).build();
this.obligationCache = CacheBuilder.newBuilder().expireAfterWrite(CACHE_TIMEOUT_MINUTES, TimeUnit.MINUTES)
.maximumSize(CACHE_MAX_ITEMS).build();

AttachmentContentProvider contentProvider = attachment -> attachmentDatabaseHandler.getAttachmentContent(attachment.getAttachmentContentId());

Expand Down Expand Up @@ -104,6 +113,7 @@ public LicenseInfoFile getLicenseInfoFile(Project project, User user, String out
Map<Release, Set<String>> releaseToAttachmentId = mapKeysToReleases(releaseIdsToSelectedAttachmentIds, user);
Collection<LicenseInfoParsingResult> projectLicenseInfoResults = getAllReleaseLicenseInfos(releaseToAttachmentId, user,
excludedLicensesPerAttachment);
Collection<ObligationParsingResult> obligationsResults = getAllReleaseObligations(releaseToAttachmentId, user);

String[] outputGeneratorClassnameAndVariant = outputGenerator.split("::");
if (outputGeneratorClassnameAndVariant.length != 2) {
Expand All @@ -116,8 +126,10 @@ public LicenseInfoFile getLicenseInfoFile(Project project, User user, String out
LicenseInfoFile licenseInfoFile = new LicenseInfoFile();

licenseInfoFile.setOutputFormatInfo(generator.getOutputFormatInfo());
String licenseInfoHeaderText = (project.isSetLicenseInfoHeaderText()) ? project.getLicenseInfoHeaderText() : getDefaultLicenseInfoHeaderText();
Object output = generator.generateOutputFile(projectLicenseInfoResults, project.getName(), project.getVersion(), licenseInfoHeaderText);

fillDefaults(project);

Object output = generator.generateOutputFile(projectLicenseInfoResults, project, obligationsResults);
if (output instanceof byte[]) {
licenseInfoFile.setGeneratedOutput((byte[]) output);
} else if (output instanceof String) {
Expand All @@ -129,6 +141,15 @@ public LicenseInfoFile getLicenseInfoFile(Project project, User user, String out
return licenseInfoFile;
}

private void fillDefaults(Project project) {
if(!project.isSetLicenseInfoHeaderText()) {
project.setLicenseInfoHeaderText(getDefaultLicenseInfoHeaderText());
}
if(!project.isSetObligationsText()) {
project.setObligationsText(getDefaultObligationsText());
}
}

@Override
public List<OutputFormatInfo> getPossibleOutputFormats() {
return outputGenerators.stream().map(OutputGenerator::getOutputFormatInfo).collect(Collectors.toList());
Expand Down Expand Up @@ -181,13 +202,61 @@ public List<LicenseInfoParsingResult> getLicenseInfoForAttachment(Release releas
filterEmptyLicenses(results);

results = assignReleaseToLicenseInfoParsingResults(results, release);
results = assignComponentToLicenseInfoParsingResults(results, release, user);

licenseInfoCache.put(attachmentContentId, results);
return results;
} catch (WrappedTException exception) {
throw exception.getCause();
}
}

private List<ObligationParsingResult> getObligationsForAttachment(Release release, String attachmentContentId, User user)
throws TException {
if (release == null) {
return Collections.singletonList(new ObligationParsingResult()
.setStatus(ObligationInfoRequestStatus.NO_APPLICABLE_SOURCE)
.setMessage(MSG_NO_RELEASE_GIVEN));
}

List<ObligationParsingResult> cachedResults = obligationCache.getIfPresent(attachmentContentId);
if (cachedResults != null) {
return cachedResults;
}

Attachment attachment = nullToEmptySet(release.getAttachments()).stream()
.filter(a -> a.getAttachmentContentId().equals(attachmentContentId)).findFirst().orElseThrow(() -> {
String message = String.format(
"Attachment selected for obligations info generation is not found in release's attachments. Release id: %s. Attachment content id: %s",
release.getId(), attachmentContentId);
return new IllegalStateException(message);
});

try {

List<LicenseInfoParser> applicableParsers = parsers.stream()
.filter(parser -> wrapTException(() -> parser.isApplicableTo(attachment, user, release))).collect(Collectors.toList());

if (applicableParsers.size() == 0) {
LOGGER.warn("No applicable parser has been found for the attachment selected for license information");
return Collections.singletonList(new ObligationParsingResult()
.setStatus(ObligationInfoRequestStatus.NO_APPLICABLE_SOURCE)
.setMessage("No applicable parser has been found for the attachment."));
} else if (applicableParsers.size() > 1) {
LOGGER.info("More than one parser claims to be able to parse attachment with contend id " + attachmentContentId);
}

List<ObligationParsingResult> results = applicableParsers.stream()
.map(parser -> wrapTException(() -> parser.getObligations(attachment, user, release)))
.collect(Collectors.toList());

obligationCache.put(attachmentContentId, results);
return results;
} catch (WrappedTException exception) {
throw exception.getCause();
}
}

private LicenseInfoParsingResult assignFileNameToLicenseInfoParsingResult(LicenseInfoParsingResult licenseInfoParsingResult, String filename) {
if (licenseInfoParsingResult.getLicenseInfo() == null) {
licenseInfoParsingResult.setLicenseInfo(new LicenseInfo());
Expand All @@ -201,6 +270,11 @@ public String getDefaultLicenseInfoHeaderText() {
return DEFAULT_LICENSE_INFO_TEXT;
}

@Override
public String getDefaultObligationsText() {
return DEFAULT_OBLIGATIONS_TEXT;
}

protected Map<Release, Set<String>> mapKeysToReleases(Map<String, Set<String>> releaseIdsToAttachmentIds, User user) throws TException {
Map<Release, Set<String>> result = Maps.newHashMap();
try {
Expand Down Expand Up @@ -243,6 +317,21 @@ protected Collection<LicenseInfoParsingResult> getAllReleaseLicenseInfos(Map<Rel
return results;
}

private Collection<ObligationParsingResult> getAllReleaseObligations(Map<Release, Set<String>> releaseToSelectedAttachmentIds, User user)
throws TException {
List<ObligationParsingResult> results = Lists.newArrayList();

for (Entry<Release, Set<String>> entry : releaseToSelectedAttachmentIds.entrySet()) {
for (String attachmentContentId : entry.getValue()) {
if (attachmentContentId != null) {
results.addAll(getObligationsForAttachment(entry.getKey(), attachmentContentId, user));
}
}
}

return results;
}

protected LicenseInfoParsingResult filterLicenses(LicenseInfoParsingResult result, Set<LicenseNameWithText> licencesToExclude) {
// make a deep copy to NOT change the original document that is cached
LicenseInfoParsingResult newResult = result.deepCopy();
Expand Down Expand Up @@ -285,6 +374,40 @@ protected List<LicenseInfoParsingResult> assignReleaseToLicenseInfoParsingResult
return parsingResults;
}

protected List<LicenseInfoParsingResult> assignComponentToLicenseInfoParsingResults(List<LicenseInfoParsingResult> parsingResults, Release release, User user) throws TException {
final ComponentService.Iface componentClient = new ThriftClients().makeComponentClient();
final Component component = componentClient.getComponentById(release.getComponentId(), user);

parsingResults.forEach(result -> {
if( component != null) {
result.setComponentType(toString(component.getComponentType()));
} else {
// just being extra defensive
result.setComponentType("Unknown component.");
}
});
return parsingResults;
}

protected String toString(ComponentType type) {
switch(type) {
case INTERNAL:
return "Internal";
case OSS:
return "OSS";
case COTS:
return "COTS";
case FREESOFTWARE:
return "Free software";
case INNER_SOURCE:
return "Inner source";
case SERVICE:
return "Service";
}

return "";
}

protected OutputGenerator<?> getOutputGeneratorByClassname(String generatorClassname) throws TException {
assertNotNull(generatorClassname);
return outputGenerators.stream()
Expand All @@ -301,9 +424,8 @@ protected OutputGenerator<?> getOutputGeneratorByClassnameAndVariant(String gene
.findFirst().orElseThrow(() -> new TException("Unknown output generator: " + generatorClassname));
}

private static String loadDefaultLicenseInfoHeaderText(){
String defaultLicenseInfoHeader = new String( CommonUtils.loadResource(LicenseInfoHandler.class, DEFAULT_LICENSE_INFO_HEADER_FILE).orElse(new byte[0]) );
defaultLicenseInfoHeader = defaultLicenseInfoHeader.replaceAll("(?m)^#.*\\n", ""); // ignore comments in template file
return defaultLicenseInfoHeader;
private static String dropCommentedLine(String TEMPLATE_FILE) {
String text = new String( CommonUtils.loadResource(LicenseInfoHandler.class, TEMPLATE_FILE).orElse(new byte[0]) );
return text.replaceAll("(?m)^#.*(?:\r?\n)?", ""); // ignore comments in template file
}
}
Loading

0 comments on commit 8d62965

Please sign in to comment.