Skip to content

Commit

Permalink
Merge pull request #690 from eclipse-passage/566482
Browse files Browse the repository at this point in the history
Bug 566482 implement license grants uploading interface
  • Loading branch information
eparovyshnaya authored Mar 28, 2021
2 parents c205019 + a204a01 commit 0900108
Show file tree
Hide file tree
Showing 22 changed files with 463 additions and 42 deletions.
1 change: 1 addition & 0 deletions bundles/org.eclipse.passage.lbc.base/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ Require-Bundle: javax.servlet;bundle-version="0.0.0",
Export-Package: org.eclipse.passage.lbc.internal.base;x-friends:="org.eclipse.passage.lbc.jetty,org.eclipse.passage.lbc.base.tests,org.eclipse.passage.lic.hc.tests",
org.eclipse.passage.lbc.internal.base.acquire;x-friends:="org.eclipse.passage.lbc.base.tests,org.eclipse.passage.lic.hc.tests",
org.eclipse.passage.lbc.internal.base.api,
org.eclipse.passage.lbc.internal.base.interaction;x-friends:="org.eclipse.passage.lbc.jetty",
org.eclipse.passage.lbc.internal.base.mine;x-friends:="org.eclipse.passage.lbc.base.tests,org.eclipse.passage.lic.hc.tests"
Bundle-ActivationPolicy: lazy
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*******************************************************************************
* Copyright (c) 2021 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lbc.internal.base.interaction;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

import org.eclipse.passage.lic.internal.api.ServiceInvocationResult;
import org.eclipse.passage.lic.internal.api.diagnostic.Trouble;
import org.eclipse.passage.lic.internal.base.BaseServiceInvocationResult;
import org.eclipse.passage.lic.internal.base.diagnostic.BaseDiagnostic;
import org.eclipse.passage.lic.internal.base.diagnostic.SumOfLists;
import org.eclipse.passage.lic.internal.base.diagnostic.code.ServiceFailedOnMorsel;
import org.eclipse.passage.lic.internal.base.io.ExternalLicense;

public final class IncomingLicense {

private final Path residence;

public IncomingLicense(String residence) {
Objects.requireNonNull(residence, "IncomingLicense:residence");//$NON-NLS-1$
this.residence = Paths.get(residence);
validateResidence();
}

public ServiceInvocationResult<List<Path>> upload() {
ServiceInvocationResult<Collection<Pack>> packs = new PacksFound(residence).get();
if (!packs.data().isPresent() || packs.data().get().isEmpty()) {
return new BaseServiceInvocationResult<>(packs.diagnostic());
}
return packs.data().get().stream()//
.map(this::uploadPack)//
.reduce(new BaseServiceInvocationResult<>(Collections.emptyList()),
new BaseServiceInvocationResult.Sum<>(new SumOfLists<>()));
}

private ServiceInvocationResult<List<Path>> uploadPack(Pack pack) {
try {
Pack.Resolved resolved = pack.resolve();
Path destination = new ExternalLicense(resolved.product()).install(pack.content());
return new BaseServiceInvocationResult<>(Collections.singletonList(destination));
} catch (Exception e) {
return failedToUploadPack(pack, e);
}
}

private BaseServiceInvocationResult<List<Path>> failedToUploadPack(Pack pack, Exception e) {
return new BaseServiceInvocationResult<>(new BaseDiagnostic(Collections.singletonList(//
new Trouble(//
new ServiceFailedOnMorsel(), //
String.format("Failed to upload %s", pack), //$NON-NLS-1$
e))));
}

private final void validateResidence() {
String info = residence.toAbsolutePath().toString();
if (!Files.exists(residence)) {
throw new IllegalArgumentException(String.format("%s does not exist", info)); //$NON-NLS-1$
}
if (!Files.isDirectory(residence)) {
throw new IllegalArgumentException(String.format("%s is not a directory", info)); //$NON-NLS-1$
}
if (!Files.isExecutable(residence)) {
throw new IllegalArgumentException(String.format("%s cannot be read", info)); //$NON-NLS-1$
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*******************************************************************************
* Copyright (c) 2021 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lbc.internal.base.interaction;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import java.util.stream.Collectors;

import org.eclipse.passage.lic.internal.api.LicensingException;

final class OnlyFileOfType {

private final Path folder;
private final String extension;

public OnlyFileOfType(Path folder, String extension) {
this.folder = folder;
this.extension = extension;
}

Path get() throws Exception {
List<Path> keys = Files.find(folder, 1, this::ofType).collect(Collectors.toList());
if (keys.size() != 1) {
throw new LicensingException(String.format("%s is expected to contain exactly one file of type %s", //$NON-NLS-1$
folder.toString(), extension));
}
return keys.get(0);
}

private boolean ofType(Path file, @SuppressWarnings("unused") BasicFileAttributes any) {
return file.getFileName().toString().endsWith(extension);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*******************************************************************************
* Copyright (c) 2021 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lbc.internal.base.interaction;

import java.nio.file.Path;
import java.util.Collections;

import org.eclipse.passage.lic.floating.model.api.FloatingLicensePack;
import org.eclipse.passage.lic.floating.model.api.ProductRef;
import org.eclipse.passage.lic.floating.model.meta.FloatingPackage;
import org.eclipse.passage.lic.internal.api.LicensedProduct;
import org.eclipse.passage.lic.internal.api.LicensingException;
import org.eclipse.passage.lic.internal.base.BaseLicensedProduct;
import org.eclipse.passage.lic.internal.base.InvalidLicensedProduct;
import org.eclipse.passage.lic.internal.base.conditions.mining.DecodedContent;
import org.eclipse.passage.lic.internal.base.io.FileKeyKeeper;
import org.eclipse.passage.lic.internal.bc.BcStreamCodec;
import org.eclipse.passage.lic.internal.emf.EObjectFromBytes;

final class Pack {

private final Path license;
private final Path key;

Pack(Path license, Path key) {
this.license = license;
this.key = key;
}

Resolved resolve() throws LicensingException {
return new Resolved();
}

Path[] content() {
return new Path[] { license, key };
}

@Override
public String toString() {
return String.format("pack license=[%s], key=[%s]", license.toAbsolutePath(), key.toAbsolutePath()); //$NON-NLS-1$
}

final class Resolved {

private final FloatingLicensePack content;

Resolved() throws LicensingException {
this.content = read(decoded());
}

private FloatingLicensePack read(byte[] bytes) throws LicensingException {
return new EObjectFromBytes<>(//
bytes, //
FloatingLicensePack.class//
).get(Collections.singletonMap(FloatingPackage.eNAME, FloatingPackage.eINSTANCE));
}

private byte[] decoded() throws LicensingException {
return new DecodedContent(//
license, //
new FileKeyKeeper(key), //
new BcStreamCodec(InvalidLicensedProduct::new) // not demanded for decoding, only for error handling
).get();
}

LicensedProduct product() {
ProductRef ref = content.getLicense().getProduct();
return new BaseLicensedProduct(ref.getProduct(), ref.getVersion());
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (c) 2021 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lbc.internal.base.interaction;

import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;

import org.eclipse.passage.lic.floating.FloatingFileExtensions;
import org.eclipse.passage.lic.internal.api.ServiceInvocationResult;
import org.eclipse.passage.lic.internal.api.diagnostic.Trouble;
import org.eclipse.passage.lic.internal.base.BaseServiceInvocationResult;
import org.eclipse.passage.lic.internal.base.SumOfCollections;
import org.eclipse.passage.lic.internal.base.diagnostic.BaseDiagnostic;
import org.eclipse.passage.lic.internal.base.diagnostic.code.NoDataOfType;
import org.eclipse.passage.lic.internal.base.diagnostic.code.ServiceFailedOnMorsel;
import org.eclipse.passage.lic.internal.base.io.PassageFileExtension;

final class PacksFound implements Supplier<ServiceInvocationResult<Collection<Pack>>> {

private final Path source;
private final String flicen = new FloatingFileExtensions.FloatingLicenseEncrypted().get();
private final String pub = new PassageFileExtension.PublicKey().get();

public PacksFound(Path source) {
this.source = source;
}

@Override
public ServiceInvocationResult<Collection<Pack>> get() {
List<ServiceInvocationResult<Collection<Pack>>> packs = new ArrayList<>();
searchThroughDirectory(source.toFile(), packs);
if (packs.isEmpty()) {
return new BaseServiceInvocationResult<Collection<Pack>>(
new Trouble(new NoDataOfType(), "floating license")); //$NON-NLS-1$
}
return packs.stream().reduce(//
new BaseServiceInvocationResult<>(Collections.emptyList()), //
new BaseServiceInvocationResult.Sum<>(new SumOfCollections<>()));
}

private void searchThroughDirectory(File parent, List<ServiceInvocationResult<Collection<Pack>>> packs) {
for (File file : parent.listFiles()) {
if (file.isDirectory()) {
searchThroughDirectory(file, packs);
} else {
maybePack(file).ifPresent(packs::add);
}
}
}

private Optional<ServiceInvocationResult<Collection<Pack>>> maybePack(File license) {
if (!license.getName().endsWith(flicen)) {
return Optional.empty();
}
Path key;
try {
key = new OnlyFileOfType(license.getParentFile().toPath(), pub).get();
} catch (Exception e) {
return Optional.of(failToFindKey(license, e));
}
return Optional.of(packIndeed(license, key));

}

private ServiceInvocationResult<Collection<Pack>> packIndeed(File license, Path key) {
return new BaseServiceInvocationResult<>(Collections.singletonList(new Pack(license.toPath(), key)));
}

private ServiceInvocationResult<Collection<Pack>> failToFindKey(File license, Exception e) {
Trouble error = new Trouble(//
new ServiceFailedOnMorsel(), //
String.format("Failed to find public key for license file %s", //$NON-NLS-1$
license.getAbsolutePath()),
e);
return new BaseServiceInvocationResult<>(new BaseDiagnostic(Collections.singletonList(error)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@
import org.eclipse.passage.lic.internal.emf.EObjectFromBytes;
import org.eclipse.passage.lic.internal.licenses.migration.tobemoved.XmiConditionTransport;

/**
* FIXME: There lots of diagnostics is spared in vain. Find a way to pass it to
* a client should the need arise
*/
final class ReassemblingMiningTool extends ArmedMiningTool {

private final String user;
Expand Down Expand Up @@ -100,9 +96,8 @@ private boolean productFits(ProductRef ref) {
private FloatingLicensePack pack(Path source) throws LicensingException {
return new EObjectFromBytes<>(//
decoded(source), //
FloatingLicensePack.class).get(//
Collections.singletonMap(FloatingPackage.eNAME, FloatingPackage.eINSTANCE)//
);
FloatingLicensePack.class//
).get(Collections.singletonMap(FloatingPackage.eNAME, FloatingPackage.eINSTANCE));
}

private BaseConditionPack noConditions(Path license) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
*******************************************************************************/
package org.eclipse.passage.lbc.internal.jetty;

import java.nio.file.Path;
import java.util.List;

import org.eclipse.passage.lbc.internal.base.interaction.IncomingLicense;
import org.eclipse.passage.lic.internal.api.ServiceInvocationResult;
import org.eclipse.passage.lic.internal.jetty.interaction.Command;
import org.eclipse.passage.lic.internal.jetty.interaction.Scope;

Expand All @@ -22,28 +27,31 @@ public UploadLicense(String scope) {
}

public void upload(String from) {
// new IncomingLicense(from).upload();
ServiceInvocationResult<List<Path>> result = new IncomingLicense(from).upload();
if (result.data().isPresent()) {
reportDestination(result.data().get());
}
reportDiagnostic(result.diagnostic());

}

public void upload(String from, String product, String version) {
// new IncomingLicense(from).uploadForProduct(product, version);
private void reportDestination(List<Path> list) {
System.out.println("Floating lincens(es) uploaded to "); //$NON-NLS-1$
list.forEach(path -> System.out.println("\t" + path.toAbsolutePath())); //$NON-NLS-1$
}

public void upload(String... args) {
if (args.length == 1) {
upload(args[0]);
} else if (args.length == 3) {
upload(args[0], args[1], args[2]);
} else {
System.out.println(help());
}
}

private String help() {
return "[fls:upload] places the given floating license pack at the Server's disposal.\n" + //$NON-NLS-1$
"Usage:\n\t" + //$NON-NLS-1$
scope.id() + ":upload <path-to-license-pack-folder>\n\t" + //$NON-NLS-1$
scope.id() + ":upload <path-to-license-pack-folder> <product-id> <product-version>\n"; //$NON-NLS-1$
return "[fls:upload] scans the given folder for floating licenses and uploads all findings at the Server's disposal.\n" //$NON-NLS-1$
+ "Usage:\n\t" //$NON-NLS-1$
+ scope.id() + ":upload <path-to-folder>\n\t"; //$NON-NLS-1$
}

}
Loading

0 comments on commit 0900108

Please sign in to comment.