Merge branch 'Feature/Add_Rest_Api_with_Java_client' of https://github.com/bsinno/hawkbit into Feature/Add_Rest_Api_with_Java_client

This commit is contained in:
SirWayne
2016-04-27 15:39:44 +02:00
15 changed files with 375 additions and 232 deletions

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.ddi.client; package org.eclipse.hawkbit.ddi.client;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.eclipse.hawkbit.ddi.client.authenctication.AuthenticationInterceptor;
import org.eclipse.hawkbit.ddi.client.resource.RootControllerResourceClient; import org.eclipse.hawkbit.ddi.client.resource.RootControllerResourceClient;
import org.eclipse.hawkbit.feign.core.client.ApplicationJsonRequestHeaderInterceptor; import org.eclipse.hawkbit.feign.core.client.ApplicationJsonRequestHeaderInterceptor;
import org.eclipse.hawkbit.feign.core.client.IgnoreMultipleConsumersProducersSpringMvcContract; import org.eclipse.hawkbit.feign.core.client.IgnoreMultipleConsumersProducersSpringMvcContract;
@@ -31,10 +32,20 @@ public class DdiDefaultFeignClient {
private final String tenant; private final String tenant;
public DdiDefaultFeignClient(final String baseUrl, final String tenant) { public DdiDefaultFeignClient(final String baseUrl, final String tenant) {
this(baseUrl, tenant, null);
}
public DdiDefaultFeignClient(final String baseUrl, final String tenant,
final AuthenticationInterceptor authenticationInterceptor) {
feignBuilder = Feign.builder().contract(new IgnoreMultipleConsumersProducersSpringMvcContract()) feignBuilder = Feign.builder().contract(new IgnoreMultipleConsumersProducersSpringMvcContract())
.requestInterceptor(new ApplicationJsonRequestHeaderInterceptor()) .requestInterceptor(new ApplicationJsonRequestHeaderInterceptor())
.requestInterceptor(new DdiAcceptedRequestInterceptor()).logLevel(Level.FULL) .requestInterceptor(new DdiAcceptedRequestInterceptor()).logLevel(Level.FULL)
.logger(new Logger.ErrorLogger()).encoder(new JacksonEncoder()).decoder(new DdiDecoder()); .logger(new Logger.ErrorLogger()).encoder(new JacksonEncoder()).decoder(new DdiDecoder());
if (authenticationInterceptor != null) {
feignBuilder.requestInterceptor(authenticationInterceptor);
}
Validate.notNull(baseUrl, "A baseUrl has to be set"); Validate.notNull(baseUrl, "A baseUrl has to be set");
Validate.notNull(tenant, "A tenant has to be set"); Validate.notNull(tenant, "A tenant has to be set");
this.baseUrl = baseUrl; this.baseUrl = baseUrl;

View File

@@ -12,11 +12,14 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.temporal.ChronoField;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.eclipse.hawkbit.ddi.client.strategy.PersistenceStrategy; import org.eclipse.hawkbit.ddi.client.authenctication.AuthenticationInterceptor;
import org.eclipse.hawkbit.ddi.client.resource.RootControllerResourceClient;
import org.eclipse.hawkbit.ddi.client.strategy.ArtifactsPersistenceStrategy;
import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback; import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback;
import org.eclipse.hawkbit.ddi.json.model.DdiArtifact; import org.eclipse.hawkbit.ddi.json.model.DdiArtifact;
import org.eclipse.hawkbit.ddi.json.model.DdiChunk; import org.eclipse.hawkbit.ddi.json.model.DdiChunk;
@@ -41,9 +44,11 @@ public class DdiExampleClient implements Runnable {
private final String controllerId; private final String controllerId;
private Long actionIdOfLastInstalltion; private Long actionIdOfLastInstalltion;
private final DdiDefaultFeignClient ddiDefaultFeignClient; private final RootControllerResourceClient rootControllerResourceClient;
private final PersistenceStrategy persistenceStrategy; private final ArtifactsPersistenceStrategy persistenceStrategy;
private STATUS clientStatus; private DdiClientStatus clientStatus;
private FinalResult finalResultOfCurrentUpdate;
/** /**
* Constructor for the DDI example client. * Constructor for the DDI example client.
@@ -58,35 +63,56 @@ public class DdiExampleClient implements Runnable {
* the persistence strategy for downloading artifacts * the persistence strategy for downloading artifacts
*/ */
public DdiExampleClient(final String baseUrl, final String controllerId, final String tenant, public DdiExampleClient(final String baseUrl, final String controllerId, final String tenant,
final PersistenceStrategy persistenceStrategy) { final ArtifactsPersistenceStrategy persistenceStrategy) {
this(baseUrl, controllerId, tenant, persistenceStrategy, null);
}
/**
* Constructor for the DDI example client.
*
* @param baseUrl
* the base url of the hawkBit server
* @param controllerId
* the controller id that will be simulated
* @param tenant
* the tenant
* @param persistenceStrategy
* the persistence strategy for downloading artifacts
* @param authenticationInterceptor
* the authentication intercepter to authenticate the DDI client,
* might be {@code null}
*/
public DdiExampleClient(final String baseUrl, final String controllerId, final String tenant,
final ArtifactsPersistenceStrategy persistenceStrategy, final AuthenticationInterceptor authenticationInterceptor) {
this.controllerId = controllerId; this.controllerId = controllerId;
this.ddiDefaultFeignClient = new DdiDefaultFeignClient(baseUrl, tenant); this.rootControllerResourceClient = new DdiDefaultFeignClient(baseUrl, tenant, authenticationInterceptor)
.getRootControllerResourceClient();
this.actionIdOfLastInstalltion = null; this.actionIdOfLastInstalltion = null;
this.persistenceStrategy = persistenceStrategy; this.persistenceStrategy = persistenceStrategy;
this.clientStatus = STATUS.DOWN; this.clientStatus = DdiClientStatus.DOWN;
} }
@Override @Override
public void run() { public void run() {
clientStatus = STATUS.UP; clientStatus = DdiClientStatus.UP;
ResponseEntity<DdiControllerBase> response; ResponseEntity<DdiControllerBase> response;
while (clientStatus == STATUS.UP) { while (clientStatus == DdiClientStatus.UP) {
LOGGER.info(" Controller {} polling from hawkBit server", controllerId); LOGGER.info(" Controller {} polling from hawkBit server", controllerId);
response = ddiDefaultFeignClient.getRootControllerResourceClient().getControllerBase(controllerId); response = rootControllerResourceClient.getControllerBase(controllerId);
final String pollingTime = response.getBody().getConfig().getPolling().getSleep(); final String pollingTimeFormReponse = response.getBody().getConfig().getPolling().getSleep();
final LocalTime localtime = LocalTime.parse(pollingTime); final LocalTime localtime = LocalTime.parse(pollingTimeFormReponse);
final long pollingIntervalInMillis = localtime.toNanoOfDay(); final long pollingIntervalInMillis = localtime.getLong(ChronoField.MILLI_OF_DAY);
final Link controllerDeploymentBaseLink = response.getBody().getLink("deploymentBase"); final Link controllerDeploymentBaseLink = response.getBody().getLink("deploymentBase");
if (controllerDeploymentBaseLink != null) { if (controllerDeploymentBaseLink != null) {
final Long actionId = getActionIdOutOfLink(controllerDeploymentBaseLink); final Long actionId = getActionIdOutOfLink(controllerDeploymentBaseLink);
final Integer resource = getResourceOutOfLink(controllerDeploymentBaseLink); final Integer resource = getResourceOutOfLink(controllerDeploymentBaseLink);
if (actionId != actionIdOfLastInstalltion) { if (actionId != actionIdOfLastInstalltion) {
finalResultOfCurrentUpdate = FinalResult.NONE;
startDownload(actionId, resource); startDownload(actionId, resource);
finishUpdateProcess(actionId);
actionIdOfLastInstalltion = actionId; actionIdOfLastInstalltion = actionId;
} }
} }
try { try {
Thread.sleep(pollingIntervalInMillis); Thread.sleep(pollingIntervalInMillis);
} catch (final InterruptedException e) { } catch (final InterruptedException e) {
@@ -99,66 +125,81 @@ public class DdiExampleClient implements Runnable {
* Stop the DDI example client * Stop the DDI example client
*/ */
public void stop() { public void stop() {
clientStatus = STATUS.DOWN; clientStatus = DdiClientStatus.DOWN;
} }
private void startDownload(final Long actionId, final Integer resource) { private void startDownload(final Long actionId, final Integer resource) {
final ResponseEntity<DdiDeploymentBase> respone = rootControllerResourceClient
final ResponseEntity<DdiDeploymentBase> respone = ddiDefaultFeignClient.getRootControllerResourceClient()
.getControllerBasedeploymentAction(controllerId, Long.valueOf(actionId), Integer.valueOf(resource)); .getControllerBasedeploymentAction(controllerId, Long.valueOf(actionId), Integer.valueOf(resource));
final DdiDeploymentBase ddiDeploymentBase = respone.getBody(); final DdiDeploymentBase ddiDeploymentBase = respone.getBody();
final List<DdiChunk> chunks = ddiDeploymentBase.getDeployment().getChunks(); final List<DdiChunk> chunks = ddiDeploymentBase.getDeployment().getChunks();
for (final DdiChunk chunk : chunks) { for (final DdiChunk chunk : chunks) {
final List<DdiArtifact> artifactList = chunk.getArtifacts(); final List<DdiArtifact> artifactList = chunk.getArtifacts();
final Link downloadLink = ddiDeploymentBase.getDeployment().getChunks().get(0).getArtifacts().get(0) if (artifactList.isEmpty()) {
.getLink("download-http"); sendFeedBackMessage(actionId, ExecutionStatus.PROCEEDING, FinalResult.NONE,
final String[] downloadLinkSep = downloadLink.getHref().split(Pattern.quote("/")); "No artifacts to download for softwaremodule " + chunk.getName());
final Long softwareModuleId = Long.valueOf(downloadLinkSep[8]); } else {
for (final DdiArtifact ddiArtifact : artifactList) { for (final DdiArtifact ddiArtifact : artifactList) {
downloadArtifact(actionId, softwareModuleId, ddiArtifact.getFilename()); if (finalResultOfCurrentUpdate != FinalResult.FAILURE) {
downloadArtifact(actionId, ddiArtifact);
} }
} }
} }
private void downloadArtifact(final Long actionId, final Long softwareModuleId, final String artifact) { }
}
private void downloadArtifact(final Long actionId, final DdiArtifact ddiArtifact) {
final String artifact = ddiArtifact.getFilename();
final Link downloadLink = ddiArtifact.getLink("download-http");
final String[] downloadLinkSep = downloadLink.getHref().split(Pattern.quote("/"));
final Long softwareModuleId = Long.valueOf(downloadLinkSep[8]);
sendFeedBackMessage(actionId, ExecutionStatus.PROCEEDING, FinalResult.NONE, sendFeedBackMessage(actionId, ExecutionStatus.PROCEEDING, FinalResult.NONE,
"Starting download of artifact " + artifact); "Starting download of artifact " + artifact);
LOGGER.info("Starting download of artifact " + artifact); LOGGER.info("Starting download of artifact " + artifact);
final ResponseEntity<InputStream> responseDownloadArtifact = ddiDefaultFeignClient final ResponseEntity<InputStream> responseDownloadArtifact = rootControllerResourceClient
.getRootControllerResourceClient().downloadArtifact(controllerId, softwareModuleId, artifact); .downloadArtifact(controllerId, softwareModuleId, artifact);
final HttpStatus statsuCode = responseDownloadArtifact.getStatusCode(); final HttpStatus statsuCode = responseDownloadArtifact.getStatusCode();
LOGGER.info("Finished download with stataus {}", statsuCode); LOGGER.info("Finished download with stataus {}", statsuCode);
try { try {
persistenceStrategy.handleInputStream(responseDownloadArtifact.getBody(), artifact); persistenceStrategy.handleInputStream(responseDownloadArtifact.getBody(), artifact);
sendFeedBackMessage(actionId, ExecutionStatus.PROCEEDING, FinalResult.NONE,
"Downloaded artifact " + artifact);
} catch (final IOException e) { } catch (final IOException e) {
sendFeedBackMessage(actionId, ExecutionStatus.CLOSED, FinalResult.FAILURE, sendFeedBackMessage(actionId, ExecutionStatus.PROCEEDING, FinalResult.NONE,
"Downloaded of artifact " + artifact + " failed"); "Downloaded of artifact " + artifact + "failed");
return; finalResultOfCurrentUpdate = FinalResult.FAILURE;
} }
sendFeedBackMessage(actionId, ExecutionStatus.PROCEEDING, FinalResult.NONE, "Downloaded artifact " + artifact);
simulateSuccessfulInstallation(actionId);
} }
private void sendFeedBackMessage(final Long actionId, final ExecutionStatus executionStatus, private void sendFeedBackMessage(final Long actionId, final ExecutionStatus executionStatus,
final FinalResult finalResult, final String message) { final FinalResult finalResult, final String message) {
final DdiResult result = new DdiResult(finalResult, null); final DdiResult result = new DdiResult(finalResult, null);
final List<String> details = new ArrayList<>(); final List<String> details = new ArrayList<>();
details.add(message); details.add(message);
final DdiStatus ddiStatus = new DdiStatus(executionStatus, result, details); final DdiStatus ddiStatus = new DdiStatus(executionStatus, result, details);
final String time = String.valueOf(LocalDateTime.now()); final String time = String.valueOf(LocalDateTime.now());
final DdiActionFeedback feedback = new DdiActionFeedback(actionId, time, ddiStatus); final DdiActionFeedback feedback = new DdiActionFeedback(actionId, time, ddiStatus);
ddiDefaultFeignClient.getRootControllerResourceClient().postBasedeploymentActionFeedback(feedback, controllerId, rootControllerResourceClient.postBasedeploymentActionFeedback(feedback, controllerId, actionId);
actionId);
LOGGER.info("Sent feedback message to HaktBit"); LOGGER.info("Sent feedback message to HaktBit");
} }
private void simulateSuccessfulInstallation(final Long actionId) { private void finishUpdateProcess(final Long actionId) {
sendFeedBackMessage(actionId, ExecutionStatus.CLOSED, FinalResult.SUCESS, "Simulated installation successful");
if (finalResultOfCurrentUpdate == FinalResult.FAILURE) {
sendFeedBackMessage(actionId, ExecutionStatus.CLOSED, FinalResult.FAILURE, "Error during update process");
}
if (finalResultOfCurrentUpdate == FinalResult.NONE) {
sendFeedBackMessage(actionId, ExecutionStatus.CLOSED, FinalResult.SUCESS,
"Simulated installation successful");
}
} }
private Long getActionIdOutOfLink(final Link controllerDeploymentBaseLink) { private Long getActionIdOutOfLink(final Link controllerDeploymentBaseLink) {
@@ -180,8 +221,8 @@ public class DdiExampleClient implements Runnable {
/** /**
* Enum for DDI running status. * Enum for DDI running status.
*/ */
public enum STATUS { public enum DdiClientStatus {
UP, DOWN; UP, DOWN;
} }
} }

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ddi.client.authenctication;
import feign.RequestInterceptor;
/**
* An DdiClient authentication intercepter to provide credential information
* e.g. in http-headers.
*/
public interface AuthenticationInterceptor extends RequestInterceptor {
}

View File

@@ -0,0 +1,34 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ddi.client.authenctication;
/**
* A factory to create {@link AuthenticationInterceptor}s.
*/
public class AuthenticationInterceptorFactory {
private AuthenticationInterceptorFactory() {
// factory class no public constructor
}
/**
* Creates a new {@link AuthenticationInterceptor} to authenticate a
* Ddi-Client via a target-security-token HTTP authorization header.
*
* @param targetSecurityToken
* the target-security-token to be added to the HTTP
* 'TargetToken' authorization header
* @return the authentication interceptor which can be used to authenticate
* an Ddi-Client
*/
public static AuthenticationInterceptor createTargetSecurityAuthenticator(final String targetSecurityToken) {
return new TargetSecurityTokenAuthenticationInterceptor(targetSecurityToken);
}
}

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ddi.client.authenctication;
import com.google.common.net.HttpHeaders;
import feign.RequestTemplate;
/**
* Implementation of the {@link AuthenticationInterceptor} to add a given
* target-security-token to the HTTP authorization header.
*/
class TargetSecurityTokenAuthenticationInterceptor implements AuthenticationInterceptor {
private final String targetSecurityToken;
/**
* @param targetSecurityToken
* the security token to add to the authorization header
*/
TargetSecurityTokenAuthenticationInterceptor(final String targetSecurityToken) {
this.targetSecurityToken = targetSecurityToken;
}
@Override
public void apply(final RequestTemplate template) {
template.header(HttpHeaders.AUTHORIZATION, "TargetToken " + targetSecurityToken);
}
}

View File

@@ -14,7 +14,7 @@ import java.io.InputStream;
/** /**
* Interface of persistence strategy. * Interface of persistence strategy.
*/ */
public interface PersistenceStrategy { public interface ArtifactsPersistenceStrategy {
/** /**
* Method handling the artifact download. * Method handling the artifact download.

View File

@@ -12,14 +12,17 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
/** /**
* Implementation of {@link PersistenceStrategy} for not downloading any * Implementation of {@link ArtifactsPersistenceStrategy} for not downloading any
* artifacts. * artifacts.
*/ */
public class DoNotSaveArtifactsStrategy implements PersistenceStrategy { public class DoNotSaveArtifacts implements ArtifactsPersistenceStrategy {
@Override @Override
public void handleInputStream(final InputStream in, final String artifactName) throws IOException { public void handleInputStream(final InputStream in, final String artifactName) throws IOException {
// do nothing
while (in.read() != -1) {
;
}
} }
} }

View File

@@ -18,15 +18,15 @@ import com.google.common.io.ByteStreams;
import com.google.common.io.Files; import com.google.common.io.Files;
/** /**
* Implementation of {@link PersistenceStrategy} for downloading artifacts to * Implementation of {@link ArtifactsPersistenceStrategy} for downloading artifacts to
* the temp directory. * the temp directory.
*/ */
public class SaveArtifactsStrategy implements PersistenceStrategy { public class SaveArtifactsToLocalTempDirectories implements ArtifactsPersistenceStrategy {
@Override @Override
public void handleInputStream(final InputStream in, final String artifactName) throws IOException { public void handleInputStream(final InputStream in, final String artifactName) throws IOException {
final File tempDir = Files.createTempDir(); final File tempDir = Files.createTempDir();
final File file = new File(tempDir + "\\" + artifactName); final File file = new File(tempDir, artifactName);
final OutputStream out = new FileOutputStream(file); final OutputStream out = new FileOutputStream(file);
ByteStreams.copy(in, out); ByteStreams.copy(in, out);
} }

View File

@@ -1,5 +1,7 @@
package org.eclipse.hawkbit.example.ddi.client; package org.eclipse.hawkbit.example.ddi.client;
import org.eclipse.hawkbit.ddi.client.DdiExampleClient;
import org.eclipse.hawkbit.ddi.client.strategy.SaveArtifactsToLocalTempDirectories;
import org.junit.Test; import org.junit.Test;
/** /**
@@ -9,14 +11,12 @@ public class AppTest {
@Test @Test
public void AppTest() { public void AppTest() {
// final DdiExampleClient ddiClient = new final DdiExampleClient ddiClient = new DdiExampleClient("http://localhost:8080/", "Einstein17", "DEFAULT",
// DdiExampleClient("http://localhost:8080/", "Einstein1", "DEFAULT", new SaveArtifactsToLocalTempDirectories());
// 2000, final Thread thread = new Thread(ddiClient);
// new SaveArtifactsStrategy()); thread.run();
// final Thread thread = new Thread(ddiClient);
// thread.run(); System.out.println("next steps........................");
//
// System.out.println("next steps........................");
} }
} }

View File

@@ -17,5 +17,5 @@ import org.springframework.cloud.netflix.feign.FeignClient;
@FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtTargetClientResource.PATH) @FeignClient(url = "${hawkbit.url:localhost:8080}/" + MgmtTargetClientResource.PATH)
public interface MgmtTargetClientResource extends MgmtTargetRestApi { public interface MgmtTargetClientResource extends MgmtTargetRestApi {
static String PATH = "/rest/v1/targets"; static String PATH = "rest/v1/targets";
} }