Created hawkbit-ddi-api maven module and resource interfaces for the module

Signed-off-by: Jonathan Philip Knoblauch <JonathanPhilip.Knoblauch@bosch-si.com>
This commit is contained in:
Jonathan Philip Knoblauch
2016-04-15 12:37:40 +02:00
parent 72d9d11199
commit 22f4d9ffcf
25 changed files with 447 additions and 426 deletions

38
hawkbit-ddi-api/pom.xml Normal file
View File

@@ -0,0 +1,38 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-ddi-api</artifactId>
<name>hawkBit :: DDI API</name>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-rest-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -6,14 +6,13 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller;
package org.eclipse.hawkbit.ddi;
/**
*
*
*
* Constants for the direct device integration rest resources.
*/
public final class ControllerConstants {
/**
* The base URL mapping of the direct device integration rest resources.
*/
@@ -37,7 +36,7 @@ public final class ControllerConstants {
/**
* Feedback channel.
*/
static final String FEEDBACK = "feedback";
public static final String FEEDBACK = "feedback";
/**
* Config data action resources.
@@ -47,17 +46,17 @@ public final class ControllerConstants {
/**
* The artifact URL mapping rest resource.
*/
static final String ARTIFACT_DOWNLOAD = "artifact";
public static final String ARTIFACT_DOWNLOAD = "artifact";
/**
* The artifact by filename URL mapping rest resource.
*/
static final String ARTIFACT_DOWNLOAD_BY_FILENAME = "/filename";
public static final String ARTIFACT_DOWNLOAD_BY_FILENAME = "/filename";
/**
* File suffix for MDH hash download (see Linux md5sum).
*/
static final String ARTIFACT_MD5_DWNL_SUFFIX = ".MD5SUM";
public static final String ARTIFACT_MD5_DWNL_SUFFIX = ".MD5SUM";
// constant class, private constructor.
private ControllerConstants() {

View File

@@ -0,0 +1,70 @@
/**
* Copyright (c) 2011-2016 Bosch Software Innovations GmbH, Germany. All rights reserved.
*
* 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.api;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.hawkbit.ddi.ControllerConstants;
import org.eclipse.hawkbit.ddi.model.Artifact;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* REST resource handling for artifact download operations.
*/
@RequestMapping(ControllerConstants.ARTIFACTS_V1_REQUEST_MAPPING)
public interface ArtifactStoreControllerDdiApi {
/**
* Handles GET {@link Artifact} download request. This could be full or
* partial download request.
*
* @param fileName
* to search for
* @param response
* to write to
* @param request
* from the client
* @param targetid
* of authenticated target
*
* @return response of the servlet which in case of success is status code
* {@link HttpStatus#OK} or in case of partial download
* {@link HttpStatus#PARTIAL_CONTENT}.
*/
@RequestMapping(method = RequestMethod.GET, value = ControllerConstants.ARTIFACT_DOWNLOAD_BY_FILENAME
+ "/{fileName}")
@ResponseBody
public ResponseEntity<Void> downloadArtifactByFilename(@PathVariable("fileName") final String fileName,
final HttpServletResponse response, final HttpServletRequest request,
@AuthenticationPrincipal final String targetid);
/**
* Handles GET {@link Artifact} MD5 checksum file download request.
*
* @param fileName
* to search for
* @param response
* to write to
*
* @return response of the servlet
*/
@RequestMapping(method = RequestMethod.GET, value = ControllerConstants.ARTIFACT_DOWNLOAD_BY_FILENAME
+ "/{fileName}" + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX)
@ResponseBody
public ResponseEntity<Void> downloadArtifactMD5ByFilename(@PathVariable("fileName") final String fileName,
final HttpServletResponse response);
}

View File

@@ -0,0 +1,218 @@
/**
* Copyright (c) 2011-2016 Bosch Software Innovations GmbH, Germany. All rights reserved.
*/
package org.eclipse.hawkbit.ddi.api;
import java.lang.annotation.Target;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.eclipse.hawkbit.ddi.ControllerConstants;
import org.eclipse.hawkbit.ddi.model.ActionFeedback;
import org.eclipse.hawkbit.ddi.model.Artifact;
import org.eclipse.hawkbit.ddi.model.Cancel;
import org.eclipse.hawkbit.ddi.model.ConfigData;
import org.eclipse.hawkbit.ddi.model.ControllerBase;
import org.eclipse.hawkbit.ddi.model.DeploymentBase;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* REST resource handling for root controller CRUD operations.
*/
@RequestMapping(ControllerConstants.BASE_V1_REQUEST_MAPPING)
public interface RootControllerDdiApi {
/**
* Returns all artifacts of a given software module and target.
*
* @param targetid
* of the {@link Target} that matches to
* {@link Target#getControllerId()}
* @param softwareModuleId
* of the {@link SoftwareModule}
* @return the response
*/
@RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts", produces = {
"application/hal+json", MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<List<org.eclipse.hawkbit.ddi.model.Artifact>> getSoftwareModulesArtifacts(
@PathVariable("targetid") final String targetid,
@PathVariable("softwareModuleId") final Long softwareModuleId);
/**
* Root resource for an individual {@link Target}.
*
* @param targetid
* of the {@link Target} that matches to
* {@link Target#getControllerId()}
* @param request
* the HTTP request injected by spring
* @return the response
*/
@RequestMapping(method = RequestMethod.GET, value = "/{targetid}", produces = { "application/hal+json",
MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<ControllerBase> getControllerBase(@PathVariable("targetid") final String targetid,
final HttpServletRequest request);
/**
* Handles GET {@link Artifact} download request. This could be full or
* partial (as specified by RFC7233 (Range Requests)) download request.
*
* @param targetid
* of the related
* @param softwareModuleId
* of the parent {@link SoftwareModule}
* @param fileName
* of the related {@link LocalArtifact}
* @param response
* of the servlet
* @param request
* from the client
*
* @return response of the servlet which in case of success is status code
* {@link HttpStatus#OK} or in case of partial download
* {@link HttpStatus#PARTIAL_CONTENT}.
*/
@RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{fileName}")
public ResponseEntity<Void> downloadArtifact(@PathVariable("targetid") final String targetid,
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("fileName") final String fileName, final HttpServletResponse response,
final HttpServletRequest request);
/**
* Handles GET {@link Artifact} MD5 checksum file download request.
*
* @param targetid
* of the related
* @param softwareModuleId
* of the parent {@link SoftwareModule}
* @param fileName
* of the related {@link LocalArtifact}
* @param response
* of the servlet
* @param request
* the HTTP request injected by spring
*
* @return {@link ResponseEntity} with status {@link HttpStatus#OK} if
* successful
*/
@RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{fileName}"
+ ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX, produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<Void> downloadArtifactMd5(@PathVariable("targetid") final String targetid,
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("fileName") final String fileName, final HttpServletResponse response,
final HttpServletRequest request);
/**
* Resource for {@link SoftwareModule} {@link UpdateAction}s.
*
* @param targetid
* of the {@link Target} that matches to
* {@link Target#getControllerId()}
* @param actionId
* of the {@link DeploymentBase} that matches to
* {@link Target#getActiveActions()}
* @param resource
* an hashcode of the resource which indicates if the action has
* been changed, e.g. from 'soft' to 'force' and the eTag needs
* to be re-generated
* @param request
* the HTTP request injected by spring
* @return the response
*/
@RequestMapping(value = "/{targetid}/" + ControllerConstants.DEPLOYMENT_BASE_ACTION
+ "/{actionId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<DeploymentBase> getControllerBasedeploymentAction(
@PathVariable("targetid") @NotEmpty final String targetid,
@PathVariable("actionId") @NotEmpty final Long actionId,
@RequestParam(value = "c", required = false, defaultValue = "-1") final int resource,
final HttpServletRequest request);
/**
* This is the feedback channel for the {@link DeploymentBase} action.
*
* @param feedback
* to provide
* @param targetid
* of the {@link Target} that matches to
* {@link Target#getControllerId()}
* @param actionId
* of the action we have feedback for
* @param request
* the HTTP request injected by spring
*
* @return the response
*/
@RequestMapping(value = "/{targetid}/" + ControllerConstants.DEPLOYMENT_BASE_ACTION + "/{actionId}/"
+ ControllerConstants.FEEDBACK, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> postBasedeploymentActionFeedback(@Valid @RequestBody final ActionFeedback feedback,
@PathVariable("targetid") final String targetid, @PathVariable("actionId") @NotEmpty final Long actionId,
final HttpServletRequest request);
/**
* This is the feedback channel for the config data action.
*
* @param configData
* as body
* @param targetid
* to provide data for
* @param request
* the HTTP request injected by spring
*
* @return status of the request
*/
@RequestMapping(value = "/{targetid}/"
+ ControllerConstants.CONFIG_DATA_ACTION, method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> putConfigData(@Valid @RequestBody final ConfigData configData,
@PathVariable("targetid") final String targetid, final HttpServletRequest request);
/**
* {@link RequestMethod.GET} method for the {@link Cancel} action.
*
* @param targetid
* ID of the calling target
* @param actionId
* of the action
* @param request
* the HTTP request injected by spring
*
* @return the {@link Cancel} response
*/
@RequestMapping(value = "/{targetid}/" + ControllerConstants.CANCEL_ACTION
+ "/{actionId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Cancel> getControllerCancelAction(@PathVariable("targetid") @NotEmpty final String targetid,
@PathVariable("actionId") @NotEmpty final Long actionId, final HttpServletRequest request);
/**
* {@link RequestMethod.POST} method receiving the {@link ActionFeedback}
* from the target.
*
* @param feedback
* the {@link ActionFeedback} from the target.
* @param targetid
* the ID of the calling target
* @param actionId
* of the action we have feedback for
* @param request
* the HTTP request injected by spring
*
* @return the {@link ActionFeedback} response
*/
@RequestMapping(value = "/{targetid}/" + ControllerConstants.CANCEL_ACTION + "/{actionId}/"
+ ControllerConstants.FEEDBACK, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> postCancelActionFeedback(@Valid @RequestBody final ActionFeedback feedback,
@PathVariable("targetid") @NotEmpty final String targetid,
@PathVariable("actionId") @NotEmpty final Long actionId, final HttpServletRequest request);
}

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import javax.validation.constraints.NotNull;
@@ -15,16 +15,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
*
* <p>
* After the SP Target has executed an action, received by a GET(URL) request it
* reports the completion of it to the SP Server with a action status message,
* i.e. with a PUT message to the feedback channel, i.e. PUT URL/feedback. This
* message could be used not only at the end of execution but also as status
* updates during a longer lasting execution period. The format of each action
* answer message is defined below at each action. But it is expected, that the
* contents of the message answers have all a similar structure: The content
* starts with a generic header and additional elements. *
* After the HawkBit Target has executed an action, received by a GET(URL)
* request it reports the completion of it to the HawkBit Server with a action
* status message, i.e. with a PUT message to the feedback channel, i.e. PUT
* URL/feedback. This message could be used not only at the end of execution but
* also as status updates during a longer lasting execution period. The format
* of each action answer message is defined below at each action. But it is
* expected, that the contents of the message answers have all a similar
* structure: The content starts with a generic header and additional elements.
* *
* </p>
*
* <p>
@@ -72,11 +72,6 @@ public class ActionFeedback {
return status;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "ActionFeedback [id=" + id + ", time=" + time + ", status=" + status + "]";

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import javax.validation.constraints.NotNull;
@@ -17,7 +17,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Download information for all artifacts related to a specific {@link Chunk}.
*
*/
public class Artifact extends ResourceSupport {
@@ -31,47 +30,26 @@ public class Artifact extends ResourceSupport {
@JsonProperty
private Long size;
/**
* @return the hashes
*/
public ArtifactHash getHashes() {
return hashes;
}
/**
* @param hashes
* the hashes to set
*/
public void setHashes(final ArtifactHash hashes) {
this.hashes = hashes;
}
/**
* @return the fileName
*/
public String getFilename() {
return filename;
}
/**
* @param fileName
* the fileName to set
*/
public void setFilename(final String fileName) {
filename = fileName;
}
/**
* @return the size
*/
public Long getSize() {
return size;
}
/**
* @param size
* the size to set
*/
public void setSize(final Long size) {
this.size = size;
}

View File

@@ -6,15 +6,15 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import javax.validation.constraints.NotNull;
/**
* Cancel action to be provided to the target.
*
*/
public class Cancel {
private final String id;
@NotNull
@@ -34,25 +34,14 @@ public class Cancel {
this.cancelAction = cancelAction;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @return the cancelAction
*/
public CancelActionToStop getCancelAction() {
return cancelAction;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Cancel [id=" + id + ", cancelAction=" + cancelAction + "]";

View File

@@ -6,15 +6,12 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.repository.model.Action;
/**
* The {@link Action} that has to be stopped by the target.
*
*/
public class CancelActionToStop {
@@ -32,18 +29,10 @@ public class CancelActionToStop {
this.stopId = stopId;
}
/**
* @return the stopId
*/
public String getStopId() {
return stopId;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "CancelAction [stopId=" + stopId + "]";

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import java.util.List;
@@ -14,7 +14,6 @@ import javax.validation.constraints.NotNull;
/**
* Deployment chunks.
*
*/
public class Chunk {
@@ -40,7 +39,6 @@ public class Chunk {
* of the artifact
* @param artifacts
* download information
*
*/
public Chunk(final String part, final String version, final String name, final List<Artifact> artifacts) {
super();
@@ -58,16 +56,10 @@ public class Chunk {
return version;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the artifacts
*/
public List<Artifact> getArtifacts() {
return artifacts;
}

View File

@@ -6,11 +6,10 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
/**
* Standard configuration for the target.
*
*/
public class Config {

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import java.util.Map;
@@ -17,7 +17,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Feedback channel for ConfigData action.
*
*/
public class ConfigData extends ActionFeedback {
@@ -35,7 +34,6 @@ public class ConfigData extends ActionFeedback {
* is the feedback itself
* @param data
* contains the attributes.
*
*/
@JsonCreator
public ConfigData(@JsonProperty(value = "id") final Long id, @JsonProperty(value = "time") final String time,
@@ -45,18 +43,10 @@ public class ConfigData extends ActionFeedback {
this.data = data;
}
/**
* @return the data
*/
public Map<String, String> getData() {
return data;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "ConfigData [data=" + data + ", toString()=" + super.toString() + "]";

View File

@@ -6,13 +6,12 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import org.springframework.hateoas.ResourceSupport;
/**
* {@link ControllerBase} resource content.
*
*/
public class ControllerBase extends ResourceSupport {
@@ -29,9 +28,6 @@ public class ControllerBase extends ResourceSupport {
this.config = config;
}
/**
* @return the config
*/
public Config getConfig() {
return config;
}

View File

@@ -6,17 +6,14 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import java.util.List;
import org.eclipse.hawkbit.repository.model.Action;
import com.fasterxml.jackson.annotation.JsonValue;
/**
* Detailed {@link UpdateAction} information.
*
*/
public class Deployment {
@@ -57,9 +54,9 @@ public class Deployment {
/**
* The handling type for the update {@link Action}.
*
*/
public enum HandlingType {
/**
* Not necessary for the command.
*/
@@ -81,20 +78,12 @@ public class Deployment {
this.name = name;
}
/**
* @return the name
*/
@JsonValue
public String getName() {
return name;
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Deployment [download=" + download + ", update=" + update + ", chunks=" + chunks + "]";

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import javax.validation.constraints.NotNull;
@@ -16,7 +16,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/**
* {@link UpdateAction} resource.
*
*/
public class DeploymentBase extends ResourceSupport {
@@ -44,11 +43,6 @@ public class DeploymentBase extends ResourceSupport {
return deployment;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "DeploymentBase [id=" + deplyomentId + ", deployment=" + deployment + "]";

View File

@@ -6,11 +6,10 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
/**
* Polling interval for the SP target.
*
*/
public class Polling {

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import javax.validation.constraints.NotNull;
@@ -16,7 +16,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Action fulfillment progress by means of gives the achieved amount of maximal
* of possible levels.
*
*/
public class Progress {
@@ -48,11 +47,6 @@ public class Progress {
return of;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Progress [cnt=" + cnt + ", of=" + of + "]";

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import org.hibernate.validator.constraints.NotEmpty;
@@ -17,8 +17,6 @@ import com.fasterxml.jackson.annotation.JsonValue;
/**
* Result information of the action progress which can by an intermediate or
* final update.
*
*
*/
public class Result {
@@ -77,21 +75,12 @@ public class Result {
this.name = name;
}
/**
* @return the name
*/
@JsonValue
public String getName() {
return name;
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Result [finished=" + finished + ", progress=" + progress + "]";

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.controller.model;
package org.eclipse.hawkbit.ddi.model;
import java.util.List;
@@ -18,7 +18,6 @@ import com.fasterxml.jackson.annotation.JsonValue;
/**
* Details status information concerning the action processing.
*
*/
public class Status {
@@ -103,20 +102,12 @@ public class Status {
this.name = name;
}
/**
* @return the name
*/
@JsonValue
public String getName() {
return name;
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Status [execution=" + execution + ", result=" + result + ", details=" + details + "]";

View File

@@ -1,13 +1,6 @@
<!--
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
-->
<!-- 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 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
@@ -26,7 +19,7 @@
<artifactId>hawkbit-repository</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-core</artifactId>
<version>${project.version}</version>
@@ -36,6 +29,11 @@
<artifactId>hawkbit-rest-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-ddi-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>

View File

@@ -16,12 +16,12 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.cache.CacheWriteNotify;
import org.eclipse.hawkbit.ddi.api.ArtifactStoreControllerDdiApi;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper;
@@ -32,28 +32,20 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* The {@link ArtifactStoreController} of the SP server controller API that is
* queried by the SP target in order to download artifacts independent of their
* own individual resource. This is offered in addition to the
* The {@link ArtifactStoreController} of the Rollouts server controller API
* that is queried by the SP target in order to download artifacts independent
* of their own individual resource. This is offered in addition to the
* {@link RootController#downloadArtifact(String, Long, Long, javax.servlet.http.HttpServletResponse)}
* for legacy controllers that can not be fed with a download URI at runtime.
*
*
*
*
*
* TODO
*/
@RestController
@RequestMapping(ControllerConstants.ARTIFACTS_V1_REQUEST_MAPPING)
public class ArtifactStoreController {
public class ArtifactStoreController implements ArtifactStoreControllerDdiApi {
private static final Logger LOG = LoggerFactory.getLogger(ArtifactStoreController.class);
@Autowired
@@ -68,29 +60,9 @@ public class ArtifactStoreController {
@Autowired
private HawkbitSecurityProperties securityProperties;
/**
* Handles GET {@link Artifact} download request. This could be full or
* partial download request.
*
* @param fileName
* to search for
* @param response
* to write to
* @param request
* from the client
* @param targetid
* of authenticated target
*
* @return response of the servlet which in case of success is status code
* {@link HttpStatus#OK} or in case of partial download
* {@link HttpStatus#PARTIAL_CONTENT}.
*/
@RequestMapping(method = RequestMethod.GET, value = ControllerConstants.ARTIFACT_DOWNLOAD_BY_FILENAME
+ "/{fileName}")
@ResponseBody
public ResponseEntity<Void> downloadArtifactByFilename(@PathVariable final String fileName,
final HttpServletResponse response, final HttpServletRequest request,
@AuthenticationPrincipal final String targetid) {
@Override
public ResponseEntity<Void> downloadArtifactByFilename(final String fileName, final HttpServletResponse response,
final HttpServletRequest request, final String targetid) {
ResponseEntity<Void> result;
final List<LocalArtifact> foundArtifacts = artifactManagement.findLocalArtifactByFilename(fileName);
@@ -112,8 +84,7 @@ public class ArtifactStoreController {
final DbArtifact file = artifactManagement.loadLocalArtifactBinary(artifact);
// we set a download status only if we are aware of the
// targetid, i.e.
// authenticated and not anonymous
// targetid, i.e. authenticated and not anonymous
if (targetid != null && !"anonymous".equals(targetid)) {
final Action action = checkAndReportDownloadByTarget(request, targetid, artifact);
result = RestResourceConversionHelper.writeFileResponse(artifact, response, request, file,
@@ -124,10 +95,31 @@ public class ArtifactStoreController {
}
}
return result;
}
@Override
public ResponseEntity<Void> downloadArtifactMD5ByFilename(final String fileName,
final HttpServletResponse response) {
final List<LocalArtifact> foundArtifacts = artifactManagement.findLocalArtifactByFilename(fileName);
if (foundArtifacts.isEmpty()) {
LOG.warn("Softeare artifact with name {} could not be found.", fileName);
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
} else if (foundArtifacts.size() > 1) {
LOG.error("Softeare artifact name {} is not unique.", fileName);
}
try {
DataConversionHelper.writeMD5FileResponse(fileName, response, foundArtifacts.get(0));
} catch (final IOException e) {
LOG.error("Failed to stream MD5 File", e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<>(HttpStatus.OK);
}
private Action checkAndReportDownloadByTarget(final HttpServletRequest request, final String targetid,
final LocalArtifact artifact) {
final Target target = controllerManagement.updateLastTargetQuery(targetid,
@@ -151,38 +143,4 @@ public class ArtifactStoreController {
return action;
}
/**
* Handles GET {@link Artifact} MD5 checksum file download request.
*
* @param fileName
* to search for
* @param response
* to write to
*
* @return response of the servlet
*/
@RequestMapping(method = RequestMethod.GET, value = ControllerConstants.ARTIFACT_DOWNLOAD_BY_FILENAME
+ "/{fileName}" + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX)
@ResponseBody
public ResponseEntity<Void> downloadArtifactMD5ByFilename(@PathVariable final String fileName,
final HttpServletResponse response) {
final List<LocalArtifact> foundArtifacts = artifactManagement.findLocalArtifactByFilename(fileName);
if (foundArtifacts.isEmpty()) {
LOG.warn("Softeare artifact with name {} could not be found.", fileName);
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
} else if (foundArtifacts.size() > 1) {
LOG.error("Softeare artifact name {} is not unique.", fileName);
}
try {
DataConversionHelper.writeMD5FileResponse(fileName, response, foundArtifacts.get(0));
} catch (final IOException e) {
LOG.error("Failed to stream MD5 File", e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -20,11 +20,12 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
import org.eclipse.hawkbit.api.UrlProtocol;
import org.eclipse.hawkbit.controller.model.Artifact;
import org.eclipse.hawkbit.controller.model.Chunk;
import org.eclipse.hawkbit.controller.model.Config;
import org.eclipse.hawkbit.controller.model.ControllerBase;
import org.eclipse.hawkbit.controller.model.Polling;
import org.eclipse.hawkbit.ddi.ControllerConstants;
import org.eclipse.hawkbit.ddi.model.Artifact;
import org.eclipse.hawkbit.ddi.model.Chunk;
import org.eclipse.hawkbit.ddi.model.Config;
import org.eclipse.hawkbit.ddi.model.ControllerBase;
import org.eclipse.hawkbit.ddi.model.Polling;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.LocalArtifact;

View File

@@ -20,9 +20,6 @@ import org.springframework.stereotype.Controller;
/**
* Annotation to enable {@link ComponentScan} in the resource package to setup
* all {@link Controller} annotated classes and setup the Direct Device API.
*
*
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)

View File

@@ -13,15 +13,9 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
/**
* Thrown if artifact content streaming to client failed.
*
*
*
*
*/
public final class FileSteamingFailedException extends SpServerRtException {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
@@ -33,6 +27,8 @@ public final class FileSteamingFailedException extends SpServerRtException {
}
/**
* Constructor with Throwable.
*
* @param cause
* for the exception
*/
@@ -41,6 +37,8 @@ public final class FileSteamingFailedException extends SpServerRtException {
}
/**
* Constructor with error string.
*
* @param message
* of the error
*/

View File

@@ -18,16 +18,17 @@ import javax.validation.Valid;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.cache.CacheWriteNotify;
import org.eclipse.hawkbit.controller.model.ActionFeedback;
import org.eclipse.hawkbit.controller.model.Cancel;
import org.eclipse.hawkbit.controller.model.CancelActionToStop;
import org.eclipse.hawkbit.controller.model.Chunk;
import org.eclipse.hawkbit.controller.model.ConfigData;
import org.eclipse.hawkbit.controller.model.ControllerBase;
import org.eclipse.hawkbit.controller.model.Deployment;
import org.eclipse.hawkbit.controller.model.Deployment.HandlingType;
import org.eclipse.hawkbit.controller.model.DeploymentBase;
import org.eclipse.hawkbit.controller.model.Result.FinalResult;
import org.eclipse.hawkbit.ddi.api.RootControllerDdiApi;
import org.eclipse.hawkbit.ddi.model.ActionFeedback;
import org.eclipse.hawkbit.ddi.model.Cancel;
import org.eclipse.hawkbit.ddi.model.CancelActionToStop;
import org.eclipse.hawkbit.ddi.model.Chunk;
import org.eclipse.hawkbit.ddi.model.ConfigData;
import org.eclipse.hawkbit.ddi.model.ControllerBase;
import org.eclipse.hawkbit.ddi.model.Deployment;
import org.eclipse.hawkbit.ddi.model.Deployment.HandlingType;
import org.eclipse.hawkbit.ddi.model.DeploymentBase;
import org.eclipse.hawkbit.ddi.model.Result.FinalResult;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.SoftwareManagement;
@@ -35,7 +36,6 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
@@ -49,26 +49,23 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* The {@link RootController} of the SP server controller API that is queried by
* the SP controller in order to pull {@link Action}s that have to be fullfilled
* and report status updates concerning the {@link Action} processing.
* The {@link RootController} of the hawkBit server controller API that is
* queried by the hawkBit controller in order to pull {@link Action}s that have
* to be fulfilled and report status updates concerning the {@link Action}
* processing.
*
* Transactional (read-write) as all queries at least update the last poll time.
*
*/
@RestController
@RequestMapping(ControllerConstants.BASE_V1_REQUEST_MAPPING)
public class RootController {
public class RootController implements RootControllerDdiApi {
private static final Logger LOG = LoggerFactory.getLogger(RootController.class);
private static final String GIVEN_ACTION_IS_NOT_ASSIGNED_TO_GIVEN_TARGET = "given action ({}) is not assigned to given target ({}).";
@@ -94,19 +91,8 @@ public class RootController {
@Autowired
private ArtifactUrlHandler artifactUrlHandler;
/**
* Returns all artifacts of a given software module and target.
*
* @param targetid
* of the {@link Target} that matches to
* {@link Target#getControllerId()}
* @param softwareModuleId
* of the {@link SoftwareModule}
* @return the response
*/
@RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts", produces = {
"application/hal+json", MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<List<org.eclipse.hawkbit.controller.model.Artifact>> getSoftwareModulesArtifacts(
@Override
public ResponseEntity<List<org.eclipse.hawkbit.ddi.model.Artifact>> getSoftwareModulesArtifacts(
@PathVariable final String targetid, @PathVariable final Long softwareModuleId) {
LOG.debug("getSoftwareModulesArtifacts({})", targetid);
@@ -122,18 +108,7 @@ public class RootController {
HttpStatus.OK);
}
/**
* Root resource for an individual {@link Target}.
*
* @param targetid
* of the {@link Target} that matches to
* {@link Target#getControllerId()}
* @param request
* the HTTP request injected by spring
* @return the response
*/
@RequestMapping(method = RequestMethod.GET, value = "/{targetid}", produces = { "application/hal+json",
MediaType.APPLICATION_JSON_VALUE })
@Override
public ResponseEntity<ControllerBase> getControllerBase(@PathVariable final String targetid,
final HttpServletRequest request) {
LOG.debug("getControllerBase({})", targetid);
@@ -154,26 +129,7 @@ public class RootController {
HttpStatus.OK);
}
/**
* Handles GET {@link Artifact} download request. This could be full or
* partial (as specified by RFC7233 (Range Requests)) download request.
*
* @param targetid
* of the related
* @param softwareModuleId
* of the parent {@link SoftwareModule}
* @param fileName
* of the related {@link LocalArtifact}
* @param response
* of the servlet
* @param request
* from the client
*
* @return response of the servlet which in case of success is status code
* {@link HttpStatus#OK} or in case of partial download
* {@link HttpStatus#PARTIAL_CONTENT}.
*/
@RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{fileName}")
@Override
public ResponseEntity<Void> downloadArtifact(@PathVariable final String targetid,
@PathVariable final Long softwareModuleId, @PathVariable final String fileName,
final HttpServletResponse response, final HttpServletRequest request) {
@@ -198,9 +154,7 @@ public class RootController {
result = RestResourceConversionHelper.writeFileResponse(artifact, response, request, file,
cacheWriteNotify, action.getId());
}
}
return result;
}
@@ -228,25 +182,7 @@ public class RootController {
return null == module || !module.getLocalArtifactByFilename(fileName).isPresent();
}
/**
* Handles GET {@link Artifact} MD5 checksum file download request.
*
* @param targetid
* of the related
* @param softwareModuleId
* of the parent {@link SoftwareModule}
* @param fileName
* of the related {@link LocalArtifact}
* @param response
* of the servlet
* @param request
* the HTTP request injected by spring
*
* @return {@link ResponseEntity} with status {@link HttpStatus#OK} if
* successful
*/
@RequestMapping(method = RequestMethod.GET, value = "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{fileName}"
+ ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX, produces = MediaType.TEXT_PLAIN_VALUE)
@Override
public ResponseEntity<Void> downloadArtifactMd5(@PathVariable final String targetid,
@PathVariable final Long softwareModuleId, @PathVariable final String fileName,
final HttpServletResponse response, final HttpServletRequest request) {
@@ -271,25 +207,7 @@ public class RootController {
return new ResponseEntity<>(HttpStatus.OK);
}
/**
* Resource for {@link SoftwareModule} {@link UpdateAction}s.
*
* @param targetid
* of the {@link Target} that matches to
* {@link Target#getControllerId()}
* @param actionId
* of the {@link DeploymentBase} that matches to
* {@link Target#getActiveActions()}
* @param resource
* an hashcode of the resource which indicates if the action has
* been changed, e.g. from 'soft' to 'force' and the eTag needs
* to be re-generated
* @param request
* the HTTP request injected by spring
* @return the response
*/
@RequestMapping(value = "/{targetid}/" + ControllerConstants.DEPLOYMENT_BASE_ACTION
+ "/{actionId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@Override
public ResponseEntity<DeploymentBase> getControllerBasedeploymentAction(
@PathVariable @NotEmpty final String targetid, @PathVariable @NotEmpty final Long actionId,
@RequestParam(value = "c", required = false, defaultValue = "-1") final int resource,
@@ -325,23 +243,7 @@ public class RootController {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
/**
* This is the feedback channel for the {@link DeploymentBase} action.
*
* @param feedback
* to provide
* @param targetid
* of the {@link Target} that matches to
* {@link Target#getControllerId()}
* @param actionId
* of the action we have feedback for
* @param request
* the HTTP request injected by spring
*
* @return the response
*/
@RequestMapping(value = "/{targetid}/" + ControllerConstants.DEPLOYMENT_BASE_ACTION + "/{actionId}/"
+ ControllerConstants.FEEDBACK, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@Override
public ResponseEntity<Void> postBasedeploymentActionFeedback(@Valid @RequestBody final ActionFeedback feedback,
@PathVariable final String targetid, @PathVariable @NotEmpty final Long actionId,
final HttpServletRequest request) {
@@ -369,8 +271,9 @@ public class RootController {
return new ResponseEntity<>(HttpStatus.GONE);
}
controllerManagement.addUpdateActionStatus(generateUpdateStatus(feedback, targetid, feedback.getId(), action),
action);
controllerManagement.addUpdateActionStatus(
generateUpdateStatus(feedback, targetid, feedback.getId(), action), action);
return new ResponseEntity<>(HttpStatus.OK);
@@ -437,20 +340,7 @@ public class RootController {
}
}
/**
* This is the feedback channel for the config data action.
*
* @param configData
* as body
* @param targetid
* to provide data for
* @param request
* the HTTP request injected by spring
*
* @return status of the request
*/
@RequestMapping(value = "/{targetid}/"
+ ControllerConstants.CONFIG_DATA_ACTION, method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
@Override
public ResponseEntity<Void> putConfigData(@Valid @RequestBody final ConfigData configData,
@PathVariable final String targetid, final HttpServletRequest request) {
controllerManagement.updateLastTargetQuery(targetid,
@@ -461,20 +351,7 @@ public class RootController {
return new ResponseEntity<>(HttpStatus.OK);
}
/**
* {@link RequestMethod.GET} method for the {@link Cancel} action.
*
* @param targetid
* ID of the calling target
* @param actionId
* of the action
* @param request
* the HTTP request injected by spring
*
* @return the {@link Cancel} response
*/
@RequestMapping(value = "/{targetid}/" + ControllerConstants.CANCEL_ACTION
+ "/{actionId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@Override
public ResponseEntity<Cancel> getControllerCancelAction(@PathVariable @NotEmpty final String targetid,
@PathVariable @NotEmpty final Long actionId, final HttpServletRequest request) {
LOG.debug("getControllerCancelAction({})", targetid);
@@ -503,24 +380,7 @@ public class RootController {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
/**
* {@link RequestMethod.POST} method receiving the {@link ActionFeedback}
* from the target.
*
* @param feedback
* the {@link ActionFeedback} from the target.
* @param targetid
* the ID of the calling target
* @param actionId
* of the action we have feedback for
* @param request
* the HTTP request injected by spring
*
* @return the {@link ActionFeedback} response
*/
@RequestMapping(value = "/{targetid}/" + ControllerConstants.CANCEL_ACTION + "/{actionId}/"
+ ControllerConstants.FEEDBACK, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@Override
public ResponseEntity<Void> postCancelActionFeedback(@Valid @RequestBody final ActionFeedback feedback,
@PathVariable @NotEmpty final String targetid, @PathVariable @NotEmpty final Long actionId,
final HttpServletRequest request) {

14
pom.xml
View File

@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
@@ -7,9 +8,7 @@
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@@ -27,6 +26,7 @@
<modules>
<module>hawkbit-dmf-api</module>
<module>hawkbit-rest-api</module>
<module>hawkbit-ddi-api</module>
<module>hawkbit-core</module>
<module>hawkbit-security-core</module>
<module>hawkbit-repository</module>
@@ -40,7 +40,7 @@
<module>hawkbit-cache-redis</module>
<module>hawkbit-test-report</module>
<module>examples</module>
</modules>
</modules>
<scm>
@@ -244,7 +244,7 @@
</goals>
</pluginExecutionFilter>
<action>
<ignore />
<ignore/>
</action>
</pluginExecution>
<pluginExecution>
@@ -258,7 +258,7 @@
</goals>
</pluginExecutionFilter>
<action>
<ignore />
<ignore/>
</action>
</pluginExecution>
</pluginExecutions>
@@ -626,4 +626,4 @@
</dependency>
</dependencies>
</dependencyManagement>
</project>
</project>