Merge branch 'master' into feature_boot_13_sec_41

Conflicts:
	hawkbit-artifact-repository-mongo/src/test/java/org/eclipse/hawkbit/artifact/FreePortFileWriter.java
	hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/FreePortFileWriter.java


Signed-off-by: Kai Zimmermann <kai.zimmermann@bosch-si.com>
This commit is contained in:
Kai Zimmermann
2016-08-19 08:35:58 +02:00
211 changed files with 3171 additions and 2044 deletions

0
3rd-dependencies/listDeps.sh Normal file → Executable file
View File

View File

@@ -24,6 +24,12 @@ The simulator has user authentication enabled in **cloud profile**. Default cred
This can be configured/disabled by spring boot properties
## hawkBit APIs
The simulator supports `DDI` as well as the `DMF` integration APIs.
In case there is no AMQP message broker (like rabbitMQ) running, you can disable the AMQP support for the device simulator, so the simulator is not trying to connect to an amqp message broker.
Configuration property `hawkbit.device.simulator.amqp.enabled=true`
## Usage
### Graphical User Interface

View File

@@ -17,6 +17,4 @@ applications:
services:
- dmf-rabbit
env:
SPRING_PROFILES_ACTIVE: cloud,amqp
CF_STAGING_TIMEOUT: 15
CF_STARTUP_TIMEOUT: 15
SPRING_PROFILES_ACTIVE: cloud

View File

@@ -118,6 +118,16 @@ public class DeviceSimulatorUpdater {
}
private static final class DeviceSimulatorUpdateThread implements Runnable {
/**
*
*/
private static final String BUT_GOT_LOG_MESSAGE = " but got: ";
/**
*
*/
private static final String DOWNLOAD_LOG_MESSAGE = "Download ";
private static final int MINIMUM_TOKENLENGTH_FOR_HINT = 6;
private static final Random rndSleep = new SecureRandom();
@@ -187,7 +197,7 @@ public class DeviceSimulatorUpdater {
return result;
}
private boolean isErrorResponse(final UpdateStatus status) {
private static boolean isErrorResponse(final UpdateStatus status) {
if (status == null) {
return false;
}
@@ -212,60 +222,73 @@ public class DeviceSimulatorUpdater {
LOGGER.debug("Downloading {} with token {}, expected sha1 hash {} and size {}", url,
hideTokenDetails(targetToken), sha1Hash, size);
long overallread = 0;
try {
final CloseableHttpClient httpclient = createHttpClientThatAcceptsAllServerCerts();
final HttpGet request = new HttpGet(url);
request.addHeader(HttpHeaders.AUTHORIZATION, "TargetToken " + targetToken);
final String sha1HashResult;
try (final CloseableHttpResponse response = httpclient.execute(request)) {
if (response.getStatusLine().getStatusCode() != HttpStatus.OK.value()) {
final String message = wrongStatusCode(url, response);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
if (response.getEntity().getContentLength() != size) {
final String message = wrongContentLength(url, size, response);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
// Exception squid:S2070 - not used for hashing sensitive
// data
@SuppressWarnings("squid:S2070")
final MessageDigest md = MessageDigest.getInstance("SHA-1");
try (final BufferedOutputStream bdos = new BufferedOutputStream(
new DigestOutputStream(ByteStreams.nullOutputStream(), md))) {
try (BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent())) {
overallread = ByteStreams.copy(bis, bdos);
}
}
if (overallread != size) {
final String message = incompleteRead(url, size, overallread);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
sha1HashResult = BaseEncoding.base16().lowerCase().encode(md.digest());
}
if (!sha1Hash.equalsIgnoreCase(sha1HashResult)) {
final String message = wrongHash(url, sha1Hash, overallread, sha1HashResult);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
return readAndCheckDownloadUrl(url, targetToken, sha1Hash, size);
} catch (IOException | KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
LOGGER.error("Failed to download" + url, e);
return new UpdateStatus(ResponseStatus.ERROR, "Failed to download " + url + ": " + e.getMessage());
}
}
private static UpdateStatus readAndCheckDownloadUrl(final String url, final String targetToken,
final String sha1Hash, final long size)
throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, IOException {
long overallread;
final CloseableHttpClient httpclient = createHttpClientThatAcceptsAllServerCerts();
final HttpGet request = new HttpGet(url);
request.addHeader(HttpHeaders.AUTHORIZATION, "TargetToken " + targetToken);
final String sha1HashResult;
try (final CloseableHttpResponse response = httpclient.execute(request)) {
if (response.getStatusLine().getStatusCode() != HttpStatus.OK.value()) {
final String message = wrongStatusCode(url, response);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
if (response.getEntity().getContentLength() != size) {
final String message = wrongContentLength(url, size, response);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
// Exception squid:S2070 - not used for hashing sensitive
// data
@SuppressWarnings("squid:S2070")
final MessageDigest md = MessageDigest.getInstance("SHA-1");
overallread = getOverallRead(response, md);
if (overallread != size) {
final String message = incompleteRead(url, size, overallread);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
sha1HashResult = BaseEncoding.base16().lowerCase().encode(md.digest());
}
if (!sha1Hash.equalsIgnoreCase(sha1HashResult)) {
final String message = wrongHash(url, sha1Hash, overallread, sha1HashResult);
return new UpdateStatus(ResponseStatus.ERROR, message);
}
final String message = "Downloaded " + url + " (" + overallread + " bytes)";
LOGGER.debug(message);
return new UpdateStatus(ResponseStatus.SUCCESSFUL, message);
}
private static long getOverallRead(final CloseableHttpResponse response, final MessageDigest md)
throws IOException {
long overallread;
try (final BufferedOutputStream bdos = new BufferedOutputStream(
new DigestOutputStream(ByteStreams.nullOutputStream(), md))) {
try (BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent())) {
overallread = ByteStreams.copy(bis, bdos);
}
}
return overallread;
}
private static String hideTokenDetails(final String targetToken) {
if (targetToken == null) {
return "<NULL!>";
@@ -285,29 +308,30 @@ public class DeviceSimulatorUpdater {
private static String wrongHash(final String url, final String sha1Hash, final long overallread,
final String sha1HashResult) {
final String message = "Download " + url + " failed with SHA1 hash missmatch (Expected: " + sha1Hash
+ " but got: " + sha1HashResult + ") (" + overallread + " bytes)";
final String message = DOWNLOAD_LOG_MESSAGE + url + " failed with SHA1 hash missmatch (Expected: "
+ sha1Hash + BUT_GOT_LOG_MESSAGE + sha1HashResult + ") (" + overallread + " bytes)";
LOGGER.error(message);
return message;
}
private static String incompleteRead(final String url, final long size, final long overallread) {
final String message = "Download " + url + " is incomplete (Expected: " + size + " but got: " + overallread
+ ")";
final String message = DOWNLOAD_LOG_MESSAGE + url + " is incomplete (Expected: " + size
+ BUT_GOT_LOG_MESSAGE + overallread + ")";
LOGGER.error(message);
return message;
}
private static String wrongContentLength(final String url, final long size,
final CloseableHttpResponse response) {
final String message = "Download " + url + " has wrong content length (Expected: " + size + " but got: "
+ response.getEntity().getContentLength() + ")";
final String message = DOWNLOAD_LOG_MESSAGE + url + " has wrong content length (Expected: " + size
+ BUT_GOT_LOG_MESSAGE + response.getEntity().getContentLength() + ")";
LOGGER.error(message);
return message;
}
private static String wrongStatusCode(final String url, final CloseableHttpResponse response) {
final String message = "Download " + url + " failed (" + response.getStatusLine().getStatusCode() + ")";
final String message = DOWNLOAD_LOG_MESSAGE + url + " failed (" + response.getStatusLine().getStatusCode()
+ ")";
LOGGER.error(message);
return message;
}
@@ -339,4 +363,5 @@ public class DeviceSimulatorUpdater {
*/
void updateFinished(AbstractSimulatedDevice device, final Long actionId);
}
}

View File

@@ -72,6 +72,7 @@ public class SimulatedDeviceFactory {
final int pollDelaySec, final URL baseEndpoint, final String gatewayToken) {
switch (protocol) {
case DMF_AMQP:
spSenderService.createOrUpdateThing(tenant, id);
return new DMFSimulatedDevice(id, tenant, spSenderService, pollDelaySec);
case DDI_HTTP:
final ControllerResource controllerResource = Feign.builder().logger(new Logger.ErrorLogger())

View File

@@ -8,11 +8,13 @@
*/
package org.eclipse.hawkbit.simulator;
import static org.eclipse.hawkbit.simulator.amqp.AmqpProperties.CONFIGURATION_PREFIX;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Protocol;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.amqp.AmqpProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -21,22 +23,19 @@ import org.springframework.web.bind.annotation.RestController;
/**
* REST endpoint for controlling the device simulator.
*
*
*
*/
@RestController
public class SimulationController {
@Autowired
private SpSenderService spSenderService;
@Autowired
private DeviceSimulatorRepository repository;
@Autowired
private SimulatedDeviceFactory deviceFactory;
@Autowired
private AmqpProperties amqpProperties;
/**
* The start resource to start a device creation.
*
@@ -82,6 +81,12 @@ public class SimulationController {
return ResponseEntity.badRequest().body("query param api only allows value of 'dmf' or 'ddi'");
}
if (protocol == Protocol.DMF_AMQP && isDmfDisabled()) {
return ResponseEntity.badRequest()
.body("The AMQP interface has been disabled, to use DMF protocol you need to enable the AMQP interface via '"
+ CONFIGURATION_PREFIX + ".enabled=true'");
}
for (int i = 0; i < amount; i++) {
final String deviceId = name + i;
repository.add(deviceFactory.createSimulatedDevice(deviceId, tenant, protocol, pollDelay, new URL(endpoint),
@@ -90,4 +95,8 @@ public class SimulationController {
return ResponseEntity.ok("Updated " + amount + " DMF connected targets!");
}
private boolean isDmfDisabled() {
return !amqpProperties.isEnabled();
}
}

View File

@@ -11,7 +11,7 @@ package org.eclipse.hawkbit.simulator;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.amqp.AmqpProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -32,24 +32,27 @@ public class SimulatorStartup implements ApplicationListener<ContextRefreshedEve
@Autowired
private SimulationProperties simulationProperties;
@Autowired
private SpSenderService spSenderService;
@Autowired
private DeviceSimulatorRepository repository;
@Autowired
private SimulatedDeviceFactory deviceFactory;
@Autowired
private AmqpProperties amqpProperties;
@Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
simulationProperties.getAutostarts().forEach(autostart -> {
for (int i = 0; i < autostart.getAmount(); i++) {
final String deviceId = autostart.getName() + i;
try {
repository.add(deviceFactory.createSimulatedDevice(deviceId, autostart.getTenant(),
autostart.getApi(), autostart.getPollDelay(), new URL(autostart.getEndpoint()),
autostart.getGatewayToken()));
if (amqpProperties.isEnabled()) {
repository.add(deviceFactory.createSimulatedDevice(deviceId, autostart.getTenant(),
autostart.getApi(), autostart.getPollDelay(), new URL(autostart.getEndpoint()),
autostart.getGatewayToken()));
}
} catch (final MalformedURLException e) {
LOGGER.error("Creation of simulated device at startup failed.", e);
}

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.simulator.amqp;
import static org.eclipse.hawkbit.simulator.amqp.AmqpProperties.CONFIGURATION_PREFIX;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
@@ -27,6 +29,7 @@ import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -39,6 +42,7 @@ import org.springframework.retry.support.RetryTemplate;
*/
@Configuration
@EnableConfigurationProperties(AmqpProperties.class)
@ConditionalOnProperty(prefix = CONFIGURATION_PREFIX, name = "enabled")
public class AmqpConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(AmqpConfiguration.class);

View File

@@ -19,6 +19,17 @@ import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties("hawkbit.device.simulator.amqp")
public class AmqpProperties {
/**
* The prefix for this configuration.
*/
public static final String CONFIGURATION_PREFIX = "hawkbit.device.simulator.amqp";
/**
* Indicates if the AMQP interface is enabled for the device simulator.
*/
private boolean enabled;
/**
* Queue for receiving DMF messages from update server.
*/
@@ -84,4 +95,12 @@ public class AmqpProperties {
public void setDeadLetterTtl(final int deadLetterTtl) {
this.deadLetterTtl = deadLetterTtl;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
}

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.simulator.amqp;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import org.slf4j.Logger;
@@ -58,7 +59,7 @@ public abstract class SenderService extends MessageService {
}
message.getMessageProperties().getHeaders().remove(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME);
final String correlationId = UUID.randomUUID().toString();
message.getMessageProperties().setCorrelationId(correlationId.getBytes());
message.getMessageProperties().setCorrelationId(correlationId.getBytes(StandardCharsets.UTF_8));
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Sending message {} to exchange {} with correlationId {}", message, address, correlationId);

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.simulator.amqp;
import static org.eclipse.hawkbit.simulator.amqp.AmqpProperties.CONFIGURATION_PREFIX;
import java.util.Map;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
@@ -22,6 +24,7 @@ import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
@@ -32,6 +35,7 @@ import com.google.common.collect.Lists;
*
*/
@Component
@ConditionalOnProperty(prefix = CONFIGURATION_PREFIX, name = "enabled")
public class SpReceiverService extends ReceiverService {
private static final Logger LOGGER = LoggerFactory.getLogger(ReceiverService.class);
@@ -67,8 +71,6 @@ public class SpReceiverService extends ReceiverService {
* the incoming message
* @param type
* the action type
* @param contentType
* the content type in message header
* @param thingId
* the thing id in message header
*/
@@ -82,14 +84,11 @@ public class SpReceiverService extends ReceiverService {
private void delegateMessage(final Message message, final String type, final String thingId) {
final MessageType messageType = MessageType.valueOf(type);
switch (messageType) {
case EVENT:
if (MessageType.EVENT.equals(messageType)) {
handleEventMessage(message, thingId);
break;
default:
LOGGER.info("No valid message type property.");
break;
return;
}
LOGGER.info("No valid message type property.");
}
private void handleEventMessage(final Message message, final String thingId) {

View File

@@ -33,9 +33,10 @@ import com.vaadin.ui.Window;
* Popup dialog window for setting the values of generating the simulated
* devices, e.g. the amount.
*
* @author Michael Hirsch
*
*/
// Vaadin Inheritance
@SuppressWarnings("squid:MaximumInheritanceDepth")
public class GenerateDialog extends Window {
private static final long serialVersionUID = 1L;
@@ -49,8 +50,9 @@ public class GenerateDialog extends Window {
private final TextField pollDelayTextField;
private final TextField pollUrlTextField;
private final TextField gatewayTokenTextField;
private final OptionGroup protocolGroup;
private final Button buttonOk;
private OptionGroup protocolGroup;
private Button buttonOk;
private final boolean dmfEnabled;
/**
* Creates a new pop window for setting the configuration of simulating
@@ -59,9 +61,12 @@ public class GenerateDialog extends Window {
* @param callback
* the callback which is called when the dialog has been
* successfully confirmed.
* @param dmfEnabled
* indicates if the AMQP/DMF interface is enabled by
* configuration and if the option DMF should be enabled or not
*/
public GenerateDialog(final GenerateDialogCallback callback) {
public GenerateDialog(final GenerateDialogCallback callback, final boolean dmfEnabled) {
this.dmfEnabled = dmfEnabled;
formLayout.setSpacing(true);
formLayout.setMargin(true);
@@ -87,8 +92,8 @@ public class GenerateDialog extends Window {
gatewayTokenTextField.setColumns(50);
gatewayTokenTextField.setVisible(false);
protocolGroup = createProtocolGroup();
buttonOk = createOkButton(callback);
createProtocolGroup();
createOkButton(callback);
namePrefixTextField.addValueChangeListener(event -> checkValid());
amountTextField.addValueChangeListener(event -> checkValid());
@@ -181,26 +186,29 @@ public class GenerateDialog extends Window {
final URL basePollURL, final String gatewayToken, final Protocol protocol);
}
private OptionGroup createProtocolGroup() {
private void createProtocolGroup() {
final OptionGroup protocolGroup = new OptionGroup("Simulated Device Protocol");
this.protocolGroup = new OptionGroup("Simulated Device Protocol");
protocolGroup.addItem(Protocol.DMF_AMQP);
protocolGroup.addItem(Protocol.DDI_HTTP);
protocolGroup.select(Protocol.DMF_AMQP);
protocolGroup.setItemCaption(Protocol.DMF_AMQP, "Device Management Federation API (AMQP push)");
protocolGroup.setItemCaption(Protocol.DDI_HTTP, "Direct Device Interface (HTTP poll)");
protocolGroup.setNullSelectionAllowed(false);
protocolGroup.select(Protocol.DMF_AMQP);
protocolGroup.addValueChangeListener(event -> {
final boolean directDeviceOptionSelected = event.getProperty().getValue().equals(Protocol.DDI_HTTP);
pollUrlTextField.setVisible(directDeviceOptionSelected);
gatewayTokenTextField.setVisible(directDeviceOptionSelected);
});
return protocolGroup;
protocolGroup.setItemEnabled(Protocol.DMF_AMQP, dmfEnabled);
if (!dmfEnabled) {
protocolGroup.select(Protocol.DDI_HTTP);
}
}
private Button createOkButton(final GenerateDialogCallback callback) {
private void createOkButton(final GenerateDialogCallback callback) {
final Button buttonOk = new Button("generate");
this.buttonOk = new Button("generate");
buttonOk.setImmediate(true);
buttonOk.setIcon(FontAwesome.GEARS);
buttonOk.addClickListener(event -> {
@@ -210,14 +218,11 @@ public class GenerateDialog extends Window {
Integer.valueOf(pollDelayTextField.getValue().replace(".", "")),
new URL(pollUrlTextField.getValue()), gatewayTokenTextField.getValue(),
(Protocol) protocolGroup.getValue());
} catch (final NumberFormatException e) {
LOGGER.info(e.getMessage(), e);
} catch (final MalformedURLException e) {
} catch (final NumberFormatException | MalformedURLException e) {
LOGGER.info(e.getMessage(), e);
}
GenerateDialog.this.close();
});
return buttonOk;
}
private TextField createRequiredTextfield(final String caption, final String value, final Resource icon,
@@ -226,7 +231,7 @@ public class GenerateDialog extends Window {
return addTextFieldValues(textField, icon, validator);
}
private TextField createRequiredTextfield(final String caption, final Property dataSource, final Resource icon,
private TextField createRequiredTextfield(final String caption, final Property<?> dataSource, final Resource icon,
final Validator validator) {
final TextField textField = new TextField(caption, dataSource);
return addTextFieldValues(textField, icon, validator);

View File

@@ -17,6 +17,7 @@ import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice.Status;
import org.eclipse.hawkbit.simulator.DeviceSimulatorRepository;
import org.eclipse.hawkbit.simulator.SimulatedDeviceFactory;
import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus;
import org.eclipse.hawkbit.simulator.amqp.AmqpProperties;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.event.InitUpdate;
import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate;
@@ -57,6 +58,11 @@ import com.vaadin.ui.renderers.ProgressBarRenderer;
@SuppressWarnings("squid:MaximumInheritanceDepth")
public class SimulatorView extends VerticalLayout implements View {
/**
*
*/
private static final String HTML_SPAN = ";</span>";
private static final String NEXT_POLL_COUNTER_SEC_COL = "nextPollCounterSec";
private static final String RESPONSE_STATUS_COL = "updateStatus";
@@ -85,6 +91,9 @@ public class SimulatorView extends VerticalLayout implements View {
@Autowired
private transient EventBus eventbus;
@Autowired
private transient AmqpProperties amqpProperties;
private final Label caption = new Label("DMF/DDI Simulated Devices");
private final HorizontalLayout toolbar = new HorizontalLayout();
private final Grid grid = new Grid();
@@ -261,94 +270,94 @@ public class SimulatorView extends VerticalLayout implements View {
final String deviceId = namePrefix + index;
beanContainer.addBean(repository.add(deviceFactory.createSimulatedDevice(deviceId,
tenant.toLowerCase(), protocol, pollDelay, basePollUrl, gatewayToken)));
spSenderService.createOrUpdateThing(tenant, deviceId);
}
}));
}, amqpProperties.isEnabled()));
}
private Converter<String, Protocol> createProtocolConverter() {
return new Converter<String, Protocol>() {
private static final long serialVersionUID = 1L;
@Override
public Protocol convertToModel(final String value, final Class<? extends Protocol> targetType,
final Locale locale) {
return null;
}
@Override
public String convertToPresentation(final Protocol value, final Class<? extends String> targetType,
final Locale locale) {
switch (value) {
case DDI_HTTP:
return "DDI API (http)";
case DMF_AMQP:
return "DMF API (amqp)";
default:
return "unknown";
}
}
@Override
public Class<Protocol> getModelType() {
return Protocol.class;
}
@Override
public Class<String> getPresentationType() {
return String.class;
}
};
private ProtocolConverter createProtocolConverter() {
return new ProtocolConverter();
}
private Converter<String, Status> createStatusConverter() {
return new Converter<String, Status>() {
private static final long serialVersionUID = 1L;
private StatusConverter createStatusConverter() {
return new StatusConverter();
}
@Override
public Status convertToModel(final String value, final Class<? extends Status> targetType,
final Locale locale) {
return null;
}
public static final class ProtocolConverter implements Converter<String, Protocol> {
private static final long serialVersionUID = 1L;
@Override
public String convertToPresentation(final Status value, final Class<? extends String> targetType,
final Locale locale) {
switch (value) {
case UNKNWON:
return "<span class=\"v-icon grayicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"gray\";\">&#x"
+ Integer.toHexString(FontAwesome.QUESTION_CIRCLE.getCodepoint()) + ";</span>";
case PEDNING:
return "<span class=\"v-icon yellowicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"yellow\";\">&#x" + Integer.toHexString(FontAwesome.REFRESH.getCodepoint())
+ ";</span>";
case FINISH:
return "<span class=\"v-icon greenicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"green\";\">&#x"
+ Integer.toHexString(FontAwesome.CHECK_CIRCLE.getCodepoint()) + ";</span>";
case ERROR:
return "<span class=\"v-icon redicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"red\";\">&#x"
+ Integer.toHexString(FontAwesome.EXCLAMATION_CIRCLE.getCodepoint()) + ";</span>";
default:
throw new IllegalStateException("unknown value");
}
}
@Override
public Protocol convertToModel(final String value, final Class<? extends Protocol> targetType,
final Locale locale) {
return null;
}
@Override
public Class<Status> getModelType() {
return Status.class;
@Override
public String convertToPresentation(final Protocol value, final Class<? extends String> targetType,
final Locale locale) {
switch (value) {
case DDI_HTTP:
return "DDI API (http)";
case DMF_AMQP:
return "DMF API (amqp)";
default:
return "unknown";
}
}
@Override
public Class<String> getPresentationType() {
return String.class;
@Override
public Class<Protocol> getModelType() {
return Protocol.class;
}
@Override
public Class<String> getPresentationType() {
return String.class;
}
}
private static final class StatusConverter implements Converter<String, Status> {
private static final long serialVersionUID = 1L;
@Override
public Status convertToModel(final String value, final Class<? extends Status> targetType,
final Locale locale) {
return null;
}
@Override
public String convertToPresentation(final Status value, final Class<? extends String> targetType,
final Locale locale) {
switch (value) {
case UNKNWON:
return "<span class=\"v-icon grayicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"gray\";\">&#x" + Integer.toHexString(FontAwesome.QUESTION_CIRCLE.getCodepoint())
+ HTML_SPAN;
case PEDNING:
return "<span class=\"v-icon yellowicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"yellow\";\">&#x" + Integer.toHexString(FontAwesome.REFRESH.getCodepoint())
+ HTML_SPAN;
case FINISH:
return "<span class=\"v-icon greenicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"green\";\">&#x" + Integer.toHexString(FontAwesome.CHECK_CIRCLE.getCodepoint())
+ HTML_SPAN;
case ERROR:
return "<span class=\"v-icon redicon\" style=\"font-family: " + FontAwesome.FONT_FAMILY
+ ";\"color\":\"red\";\">&#x"
+ Integer.toHexString(FontAwesome.EXCLAMATION_CIRCLE.getCodepoint()) + HTML_SPAN;
default:
throw new IllegalStateException("unknown value");
}
};
}
@Override
public Class<Status> getModelType() {
return Status.class;
}
@Override
public Class<String> getPresentationType() {
return String.class;
}
}
}

View File

@@ -8,6 +8,7 @@
#
## Configuration for DMF communication
hawkbit.device.simulator.amqp.enabled=true
hawkbit.device.simulator.amqp.receiverConnectorQueueFromSp=simulator_receiver
hawkbit.device.simulator.amqp.deadLetterQueue=simulator_deadletter
hawkbit.device.simulator.amqp.deadLetterExchange=simulator.deadletter

View File

@@ -10,8 +10,12 @@ package org.eclipse.hawkbit.autoconfigure.amqp;
import org.eclipse.hawkbit.amqp.AmqpConfiguration;
import org.eclipse.hawkbit.amqp.annotation.EnableAmqp;
import org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ErrorHandler;
/**
* The amqp autoconfiguration.
@@ -24,4 +28,15 @@ import org.springframework.context.annotation.Configuration;
@EnableAmqp
public class AmqpAutoConfiguration {
/**
* Create default error handler bean.
*
* @return the default error handler bean
*/
@Bean
@ConditionalOnMissingBean
public ErrorHandler errorHandler() {
return new ConditionalRejectingErrorHandler();
}
}

View File

@@ -23,7 +23,7 @@ import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
/**
*
* Auto configuration for the event bus.
*
*/
@Configuration

View File

@@ -21,7 +21,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
/**
*
*
* Auto config fot the exception handler.
*/
@Configuration
@EnableAsync

View File

@@ -70,6 +70,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
@@ -112,6 +113,8 @@ public class SecurityManagedConfiguration {
*/
@Bean
@ConditionalOnMissingBean
// Exception squid:S00112 - Is aspectJ proxy
@SuppressWarnings({ "squid:S00112" })
public UserAuthenticationFilter userAuthenticationFilter() throws Exception {
return new UserAuthenticationFilterBasicAuth(configuration.getAuthenticationManager());
}
@@ -281,6 +284,9 @@ public class SecurityManagedConfiguration {
@Autowired
private SecurityProperties springSecurityProperties;
@Autowired
private SystemSecurityContext systemSecurityContext;
@Override
protected void configure(final HttpSecurity http) throws Exception {
@@ -309,14 +315,14 @@ public class SecurityManagedConfiguration {
userAuthenticationFilter.destroy();
}
}, RequestHeaderAuthenticationFilter.class)
.addFilterAfter(
new AuthenticationSuccessTenantMetadataCreationFilter(tenantAware, systemManagement),
SessionManagementFilter.class)
.addFilterAfter(new AuthenticationSuccessTenantMetadataCreationFilter(systemManagement,
systemSecurityContext), SessionManagementFilter.class)
.authorizeRequests().anyRequest().authenticated()
.antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/admin/**")
.hasAnyAuthority(SpPermission.SYSTEM_ADMIN);
httpSec.httpBasic().and().exceptionHandling().authenticationEntryPoint(basicAuthEntryPoint);
httpSec.anonymous().disable();
}
}
@@ -465,12 +471,15 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
@Autowired
private SystemManagement systemManagement;
@Autowired
private SystemSecurityContext systemSecurityContext;
@Override
public void onAuthenticationSuccess(final Authentication authentication) throws Exception {
if (authentication.getClass().equals(TenantUserPasswordAuthenticationToken.class)) {
systemManagement
.getTenantMetadata(((TenantUserPasswordAuthenticationToken) authentication).getTenant().toString());
systemSecurityContext.runAsSystemAsTenant(() -> systemManagement.getTenantMetadata(),
((TenantUserPasswordAuthenticationToken) authentication).getTenant().toString());
} else if (authentication.getClass().equals(UsernamePasswordAuthenticationToken.class)) {
// TODO: vaadin4spring-ext-security does not give us the
// fullyAuthenticatedToken
@@ -479,7 +488,8 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
// LoginView. This needs to be changed with the update of
// vaadin4spring 0.0.7 because it
// has been fixed.
systemManagement.getTenantMetadata("DEFAULT");
final String defaultTenant = "DEFAULT";
systemSecurityContext.runAsSystemAsTenant(() -> systemManagement.getTenantMetadata(), defaultTenant);
}
super.onAuthenticationSuccess(authentication);
@@ -491,13 +501,13 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
*/
class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
private final TenantAware tenantAware;
private final SystemManagement systemManagement;
private final SystemSecurityContext systemSecurityContext;
AuthenticationSuccessTenantMetadataCreationFilter(final TenantAware tenantAware,
final SystemManagement systemManagement) {
this.tenantAware = tenantAware;
AuthenticationSuccessTenantMetadataCreationFilter(final SystemManagement systemManagement,
final SystemSecurityContext systemSecurityContext) {
this.systemManagement = systemManagement;
this.systemSecurityContext = systemSecurityContext;
}
@Override
@@ -508,14 +518,16 @@ class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException {
final String currentTenant = tenantAware.getCurrentTenant();
if (currentTenant != null) {
// lazy initialize tenant meta data after successful authentication
systemManagement.getTenantMetadata(currentTenant);
}
lazyCreateTenantMetadata();
chain.doFilter(request, response);
}
private void lazyCreateTenantMetadata() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.isAuthenticated()) {
systemSecurityContext.runAsSystem(() -> systemManagement.getTenantMetadata());
}
}
@Override

View File

@@ -56,6 +56,10 @@ public class RedisConfiguration {
return new TenantAwareCacheManager(directCacheManager(), tenantAware);
}
/**
*
* @return bean for the direct cache manager.
*/
@Bean(name = "directCacheManager")
public CacheManager directCacheManager() {
return new RedisCacheManager(redisTemplate());

View File

@@ -28,7 +28,7 @@ import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
/**
*
* The distributor for events.
*
*/
@EventSubscriber
@@ -100,11 +100,11 @@ public class EventDistributor {
return topics;
}
private void logDistributingEvent(final Event event, final String channel) {
private static void logDistributingEvent(final Event event, final String channel) {
LOGGER.trace("distributing event {} from node {} to topic {}", event, NODE_ID, channel);
}
private void logNotDistributingEvent(final Event event, final String channel) {
private static void logNotDistributingEvent(final Event event, final String channel) {
LOGGER.debug("no redis template configured, event {} will not be distributed to channel {} from node {}", event,
channel, NODE_ID);
}

View File

@@ -16,9 +16,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
*/
@ConfigurationProperties("hawkbit.artifact.url")
public class ArtifactUrlHandlerProperties {
private static final String DEFAULT_IP_LOCALHOST = "127.0.0.1";
private static final String DEFAULT_PORT = "8080";
private static final String LOCALHOST = "localhost";
private final Http http = new Http();
private final Https https = new Https();
@@ -55,227 +52,45 @@ public class ArtifactUrlHandlerProperties {
}
}
/**
* Interface for declaring common properties through all supported protocols
* pattern.
*/
public interface ProtocolProperties {
/**
* @return the hostname value to resolve in the pattern.
*/
String getHostname();
/**
* @return the IP address value to resolve in the pattern.
*/
String getIp();
/**
* @return the port value to resolve in the pattern.
*/
String getPort();
/**
* @return the pattern to build the URL.
*/
String getPattern();
/**
* @return <code>true</code> if the {@link ProtocolProperties} is
* enabled.
*/
boolean isEnabled();
}
/**
* Object to hold the properties for the HTTP protocol.
*/
public static class Http implements ProtocolProperties {
private String hostname = LOCALHOST;
private String ip = DEFAULT_IP_LOCALHOST;
private String port = DEFAULT_PORT;
/**
* An ant-URL pattern with placeholder to build the URL on. The URL can
* have specific artifact placeholder.
*/
private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}";
public static class Http extends DefaultProtocolProperties {
/**
* Enables HTTP URI generation in DDI and DMF.
* Constructor.
*/
private boolean enabled = true;
@Override
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
@Override
public String getHostname() {
return hostname;
}
public void setHostname(final String hostname) {
this.hostname = hostname;
}
@Override
public String getIp() {
return ip;
}
public void setIp(final String ip) {
this.ip = ip;
}
@Override
public String getPattern() {
return pattern;
}
public void setPattern(final String urlPattern) {
this.pattern = urlPattern;
}
@Override
public String getPort() {
return port;
}
public void setPort(final String port) {
this.port = port;
public Http() {
setPattern(
"{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}");
}
}
/**
* Object to hold the properties for the HTTP protocol.
*/
public static class Https implements ProtocolProperties {
private String hostname = LOCALHOST;
private String ip = DEFAULT_IP_LOCALHOST;
private String port = DEFAULT_PORT;
/**
* An ant-URL pattern with placeholder to build the URL on. The URL can
* have specific artifact placeholder.
*/
private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}";
public static class Https extends DefaultProtocolProperties {
/**
* Enables HTTPS URI generation in DDI and DMF.
* Constructor.
*/
private boolean enabled = true;
@Override
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
@Override
public String getHostname() {
return hostname;
}
public void setHostname(final String hostname) {
this.hostname = hostname;
}
@Override
public String getIp() {
return ip;
}
public void setIp(final String ip) {
this.ip = ip;
}
@Override
public String getPattern() {
return pattern;
}
public void setPattern(final String urlPattern) {
this.pattern = urlPattern;
}
@Override
public String getPort() {
return port;
}
public void setPort(final String port) {
this.port = port;
public Https() {
setPattern(
"{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}");
}
}
/**
* Object to hold the properties for the HTTP protocol.
*/
public static class Coap implements ProtocolProperties {
private String hostname = LOCALHOST;
private String ip = DEFAULT_IP_LOCALHOST;
private String port = "5683";
/**
* An ant-URL pattern with placeholder to build the URL on. The URL can
* have specific artifact placeholder.
*/
private String pattern = "{protocol}://{ip}:{port}/fw/{tenant}/{targetId}/sha1/{artifactSHA1}";
public static class Coap extends DefaultProtocolProperties {
/**
* Enables CoAP URI generation in DMF.
* Constructor.
*/
private boolean enabled = true;
@Override
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
@Override
public String getHostname() {
return hostname;
}
public void setHostname(final String hostname) {
this.hostname = hostname;
}
@Override
public String getIp() {
return ip;
}
public void setIp(final String ip) {
this.ip = ip;
}
@Override
public String getPattern() {
return pattern;
}
public void setPattern(final String urlPattern) {
this.pattern = urlPattern;
}
@Override
public String getPort() {
return port;
}
public void setPort(final String port) {
this.port = port;
public Coap() {
setPattern("{protocol}://{ip}:{port}/fw/{tenant}/{targetId}/sha1/{artifactSHA1}");
setPort("5683");
}
}

View File

@@ -0,0 +1,79 @@
/**
* 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.api;
/**
* Object to hold the properties for the base protocols.
*/
public class DefaultProtocolProperties implements ProtocolProperties {
// The IP address is not hardcoded. It's the default value, if the IP
// address is not configured.
@SuppressWarnings("squid:S1313")
private static final String DEFAULT_IP_LOCALHOST = "127.0.0.1";
private static final String LOCALHOST = "localhost";
private String hostname = LOCALHOST;
private String ip = DEFAULT_IP_LOCALHOST;
private String port = "";
/**
* An ant-URL pattern with placeholder to build the URL on. The URL can have
* specific artifact placeholder.
*/
private String pattern;
/**
* Enables protocol.
*/
private boolean enabled = true;
@Override
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
@Override
public String getHostname() {
return hostname;
}
public void setHostname(final String hostname) {
this.hostname = hostname;
}
@Override
public String getIp() {
return ip;
}
public void setIp(final String ip) {
this.ip = ip;
}
@Override
public String getPattern() {
return pattern;
}
public void setPattern(final String urlPattern) {
this.pattern = urlPattern;
}
@Override
public String getPort() {
return port;
}
public void setPort(final String port) {
this.port = port;
}
}

View File

@@ -13,7 +13,6 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties.ProtocolProperties;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

View File

@@ -0,0 +1,40 @@
/**
* 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.api;
/**
* Interface for declaring common properties through all supported protocols
* pattern.
*/
public interface ProtocolProperties {
/**
* @return the hostname value to resolve in the pattern.
*/
String getHostname();
/**
* @return the IP address value to resolve in the pattern.
*/
String getIp();
/**
* @return the port value to resolve in the pattern.
*/
String getPort();
/**
* @return the pattern to build the URL.
*/
String getPattern();
/**
* @return <code>true</code> if the {@link ProtocolProperties} is enabled.
*/
boolean isEnabled();
}

View File

@@ -13,7 +13,7 @@ import org.springframework.cache.CacheManager;
/**
*
*
* A cache interface which handles multi tenancy.
*/
public interface TenancyCacheManager extends CacheManager {

View File

@@ -67,7 +67,7 @@ public class TenantAwareCacheManager implements TenancyCacheManager {
public Collection<String> getCacheNames() {
String currentTenant = tenantAware.getCurrentTenant();
if (currentTenant == null) {
return null;
return Collections.emptyList();
}
currentTenant = currentTenant.toUpperCase();

View File

@@ -17,7 +17,7 @@ import java.net.URI;
*
*
*/
public class CancelTargetAssignmentEvent extends AbstractEvent {
public class CancelTargetAssignmentEvent extends DefaultEvent {
private final String controllerId;
private final Long actionId;

View File

@@ -12,11 +12,10 @@ package org.eclipse.hawkbit.eventbus.event;
* Abstract event definition class which holds the necessary revsion and tenant
* information which every event needs.
*
* @author Michael Hirsch
* @see AbstractDistributedEvent for events which should be distributed to other
* cluster nodes
*/
public class AbstractEvent implements Event {
public class DefaultEvent implements Event {
private final long revision;
private final String tenant;
@@ -27,7 +26,7 @@ public class AbstractEvent implements Event {
* @param tenant
* the tenant of the event
*/
protected AbstractEvent(final long revision, final String tenant) {
protected DefaultEvent(final long revision, final String tenant) {
this.revision = revision;
this.tenant = tenant;
}

View File

@@ -9,9 +9,7 @@
package org.eclipse.hawkbit.eventbus.event;
/**
*
*
*
* The event when a target is deleted.
*/
public class TargetDeletedEvent extends AbstractDistributedEvent {

View File

@@ -15,8 +15,7 @@ package org.eclipse.hawkbit.exception;
* Generic Custom Exception to wrap the Runtime and checked exception
*
*/
public abstract class SpServerRtException extends RuntimeException {
public abstract class AbstractServerRtException extends RuntimeException {
private static final long serialVersionUID = 1L;
@@ -28,7 +27,7 @@ public abstract class SpServerRtException extends RuntimeException {
* @param error
* detail
*/
public SpServerRtException(final SpServerError error) {
public AbstractServerRtException(final SpServerError error) {
super(error.getMessage());
this.error = error;
}
@@ -41,7 +40,7 @@ public abstract class SpServerRtException extends RuntimeException {
* @param error
* detail
*/
public SpServerRtException(final String message, final SpServerError error) {
public AbstractServerRtException(final String message, final SpServerError error) {
super(message);
this.error = error;
}
@@ -56,7 +55,7 @@ public abstract class SpServerRtException extends RuntimeException {
* @param cause
* of the exception
*/
public SpServerRtException(final String message, final SpServerError error, final Throwable cause) {
public AbstractServerRtException(final String message, final SpServerError error, final Throwable cause) {
super(message, cause);
this.error = error;
}
@@ -69,7 +68,7 @@ public abstract class SpServerRtException extends RuntimeException {
* @param cause
* of the exception
*/
public SpServerRtException(final SpServerError error, final Throwable cause) {
public AbstractServerRtException(final SpServerError error, final Throwable cause) {
super(error.getMessage(), cause);
this.error = error;
}

View File

@@ -16,7 +16,7 @@ package org.eclipse.hawkbit.exception;
*
*
*/
public class GenericSpServerException extends SpServerRtException {
public class GenericSpServerException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_GENERIC_ERROR;

View File

@@ -11,11 +11,8 @@ package org.eclipse.hawkbit.repository;
/**
* Sort fields for {@link ActionRest}.
*
*
*
*
*/
public enum ActionFields implements FieldNameProvider,FieldValueConverter<ActionFields> {
public enum ActionFields implements FieldNameProvider, FieldValueConverter<ActionFields> {
/**
* The status field.
@@ -42,13 +39,10 @@ public enum ActionFields implements FieldNameProvider,FieldValueConverter<Action
@Override
public Object convertValue(final ActionFields e, final String value) {
switch (e) {
case STATUS:
if (STATUS.equals(e)) {
return convertStatusValue(value);
default:
return value;
}
return value;
}
private static Object convertStatusValue(final String value) {
@@ -64,11 +58,9 @@ public enum ActionFields implements FieldNameProvider,FieldValueConverter<Action
@Override
public String[] possibleValues(final ActionFields e) {
switch (e) {
case STATUS:
if (STATUS.equals(e)) {
return new String[] { ACTIVE, INACTIVE };
default:
return new String[0];
}
return new String[0];
}
}

View File

@@ -22,7 +22,7 @@ public interface FieldNameProvider {
/**
* Separator for the sub attributes
*/
public static final String SUB_ATTRIBUTE_SEPERATOR = ".";
String SUB_ATTRIBUTE_SEPERATOR = ".";
/**
* @return the string representation of the underlying persistence field
@@ -30,13 +30,24 @@ public interface FieldNameProvider {
*/
String getFieldName();
/**
* Contains the sub entity the given field.
*
* @param propertyField
* the given field
* @return <true> contains <false> contains not
*/
default boolean containsSubEntityAttribute(final String propertyField) {
return FieldNameProvider.containsSubEntityAttribute(propertyField, getSubEntityAttributes());
};
}
/**
*
* @return all sub entities attributes.
*/
default List<String> getSubEntityAttributes() {
return Collections.emptyList();
};
}
/**
* the database column for the key
@@ -59,11 +70,11 @@ public interface FieldNameProvider {
/**
* Is the entity field a {@link Map}.
*
* @return
* @return <true> is a map <false> is not a map
*/
default boolean isMap() {
return getKeyFieldName() != null;
};
}
/**
* Check if a sub attribute exists.

View File

@@ -27,7 +27,7 @@ public final class DurationHelper {
* the defined min/max range.
*
*/
public static class DurationRangeValidator {
public static final class DurationRangeValidator {
final Duration min;
final Duration max;

View File

@@ -9,14 +9,14 @@
package org.eclipse.hawkbit.tenancy.configuration;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* The {@link #InvalidTenantConfigurationKeyException} is thrown when an invalid
* configuration key is used.
*
*/
public class InvalidTenantConfigurationKeyException extends SpServerRtException {
public class InvalidTenantConfigurationKeyException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_CONFIGURATION_KEY_INVALID;

View File

@@ -22,7 +22,7 @@ public interface TenantConfigurationValidator {
* @throws TenantConfigurationValidatorException
* is thrown, when parameter is invalid.
*/
default void validate(final Object tenantConfigurationValue) throws TenantConfigurationValidatorException {
default void validate(final Object tenantConfigurationValue) {
if (tenantConfigurationValue != null
&& validateToClass().isAssignableFrom(tenantConfigurationValue.getClass())) {
return;

View File

@@ -9,14 +9,14 @@
package org.eclipse.hawkbit.tenancy.configuration.validator;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Exception which is thrown, when the validation of the configuration value has
* not been successful.
*
*/
public class TenantConfigurationValidatorException extends SpServerRtException {
public class TenantConfigurationValidatorException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_CONFIGURATION_VALUE_INVALID;

View File

@@ -27,6 +27,7 @@ public class DdiArtifactHash {
* Default constructor.
*/
public DdiArtifactHash() {
// needed for json create
}
/**

View File

@@ -29,7 +29,7 @@ public class DdiChunk {
private List<DdiArtifact> artifacts;
public DdiChunk() {
// needed for json create
}
/**

View File

@@ -34,8 +34,11 @@ public class DdiConfig {
this.polling = polling;
}
/**
* Constructor.
*/
public DdiConfig() {
// needed for json create.
}
public DdiPolling getPolling() {

View File

@@ -37,7 +37,7 @@ public class DdiControllerBase extends ResourceSupport {
}
public DdiControllerBase() {
// needed for json create
}
public DdiConfig getConfig() {

View File

@@ -23,8 +23,11 @@ public class DdiDeployment {
private List<DdiChunk> chunks;
/**
* Constructor.
*/
public DdiDeployment() {
// needed for json create.
}
/**

View File

@@ -12,6 +12,7 @@ import javax.validation.constraints.NotNull;
import org.springframework.hateoas.ResourceSupport;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
@@ -21,10 +22,10 @@ public class DdiDeploymentBase extends ResourceSupport {
@JsonProperty("id")
@NotNull
private String deplyomentId;
private final String deplyomentId;
@NotNull
private DdiDeployment deployment;
private final DdiDeployment deployment;
/**
* Constructor.
@@ -34,15 +35,13 @@ public class DdiDeploymentBase extends ResourceSupport {
* @param deployment
* details.
*/
public DdiDeploymentBase(final String id, final DdiDeployment deployment) {
deplyomentId = id;
@JsonCreator
public DdiDeploymentBase(@JsonProperty("id") final String id,
@JsonProperty("deplyomentId") final DdiDeployment deployment) {
this.deplyomentId = id;
this.deployment = deployment;
}
public DdiDeploymentBase() {
}
public DdiDeployment getDeployment() {
return deployment;
}

View File

@@ -30,11 +30,15 @@ public class DdiPolling {
* between polls
*/
public DdiPolling(final String sleep) {
super();
this.sleep = sleep;
}
/**
* Constructor.
*
*/
public DdiPolling() {
// needed for json create
}
public String getSleep() {

View File

@@ -60,8 +60,8 @@ import ru.yandex.qatools.allure.annotations.Stories;
@Stories("Deployment Action Resource")
public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoDB {
private static final String HTTP_LOCALHOST = "http://localhost:8080/";
private static final String HTTPS_LOCALHOST = "https://localhost:8080/";
private static final String HTTP_LOCALHOST = "http://localhost/";
private static final String HTTPS_LOCALHOST = "https://localhost/";
@Test()
@Description("Ensures that artifacts are not found, when softare module does not exists.")

View File

@@ -8,6 +8,10 @@
*/
package org.eclipse.hawkbit.ddi.rest.resource;
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.CONTROLLER_ROLE;
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS;
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION;
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.SYSTEM_ROLE;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.startsWith;
@@ -23,7 +27,6 @@ import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
@@ -57,7 +60,8 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
@Test
@Description("Ensures that targets cannot be created e.g. in plug'n play scenarios when tenant does not exists but can be created if the tenant exists.")
@WithUser(tenantId = "tenantDoesNotExists", allSpPermissions = true, authorities = "ROLE_CONTROLLER", autoCreateTenant = false)
@WithUser(tenantId = "tenantDoesNotExists", allSpPermissions = true, authorities = { CONTROLLER_ROLE,
SYSTEM_ROLE }, autoCreateTenant = false)
public void targetCannotBeRegisteredIfTenantDoesNotExistsButWhenExists() throws Exception {
mvc.perform(get("/default-tenant/", tenantAware.getCurrentTenant())).andDo(MockMvcResultPrinter.print())
@@ -91,13 +95,11 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
// make a poll, audit information should not be changed, run as
// controller principal!
securityRule.runAs(
WithSpringAuthorityRule.withUser("controller", SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS), () -> {
mvc.perform(
get("/{tenant}/controller/v1/" + knownTargetControllerId, tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
return null;
});
securityRule.runAs(WithSpringAuthorityRule.withUser("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
mvc.perform(get("/{tenant}/controller/v1/" + knownTargetControllerId, tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
return null;
});
// verify that audit information has not changed
final Target targetVerify = targetManagement.findTargetByControllerID(knownTargetControllerId);
@@ -143,22 +145,19 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
@Description("Ensures that tenant specific polling time, which is saved in the db, is delivered to the controller.")
@WithUser(principal = "knownpricipal", allSpPermissions = false)
public void pollWithModifiedGloablPollingTime() throws Exception {
securityRule.runAs(
WithSpringAuthorityRule.withUser("tenantadmin", SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION),
() -> {
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
"00:02:00");
return null;
});
securityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION), () -> {
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
"00:02:00");
return null;
});
securityRule.runAs(
WithSpringAuthorityRule.withUser("controller", SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS), () -> {
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$config.polling.sleep", equalTo("00:02:00")));
return null;
});
securityRule.runAs(WithSpringAuthorityRule.withUser("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(jsonPath("$config.polling.sleep", equalTo("00:02:00")));
return null;
});
}
@Test

View File

@@ -37,7 +37,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.support.RetryTemplate;;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.ErrorHandler;
/**
* The spring AMQP configuration which is enabled by using the profile
@@ -263,13 +264,16 @@ public class AmqpConfiguration {
/**
* Returns the Listener factory.
*
*
* @param errorHandler
* the error hander
* @return the {@link SimpleMessageListenerContainer} that gets used receive
* AMQP messages
*/
@Bean(name = { "listenerContainerFactory" })
public RabbitListenerContainerFactory<SimpleMessageListenerContainer> listenerContainerFactory() {
return new ConfigurableRabbitListenerContainerFactory(amqpProperties, rabbitConnectionFactory);
public RabbitListenerContainerFactory<SimpleMessageListenerContainer> listenerContainerFactory(
final ErrorHandler errorHandler) {
return new ConfigurableRabbitListenerContainerFactory(amqpProperties, rabbitConnectionFactory, errorHandler);
}
private static Map<String, Object> getTTLMaxArgsAuthenticationQueue() {

View File

@@ -36,7 +36,7 @@ import org.springframework.stereotype.Component;
/**
*
*
* A controller which handles the amqp authentfication.
*/
@Component
public class AmqpControllerAuthentfication {

View File

@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.amqp;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
@@ -137,6 +138,13 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
return onMessage(message, type, tenant, getRabbitTemplate().getConnectionFactory().getVirtualHost());
}
/**
* Executed on a authentication request.
*
* @param message
* the amqp message
* @return the rpc message back to supplier.
*/
@RabbitListener(queues = "${hawkbit.dmf.rabbitmq.authenticationReceiverQueue}", containerFactory = "listenerContainerFactory")
public Message onAuthenticationRequest(final Message message) {
checkContentTypeJson(message);
@@ -152,6 +160,19 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
}
}
/**
* * Executed if a amqp message arrives.
*
* @param message
* the message
* @param type
* the type
* @param tenant
* the tenant
* @param virtualHost
* the virtual host
* @return the rpc message back to supplier.
*/
public Message onMessage(final Message message, final String type, final String tenant, final String virtualHost) {
checkContentTypeJson(message);
final SecurityContext oldContext = SecurityContextHolder.getContext();
@@ -417,7 +438,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
}
private static String convertCorrelationId(final Message message) {
return new String(message.getMessageProperties().getCorrelationId());
return new String(message.getMessageProperties().getCorrelationId(), StandardCharsets.UTF_8);
}
private Action getUpdateActionStatus(final ActionStatus actionStatus) {

View File

@@ -39,16 +39,6 @@ public class BaseAmqpService {
this.rabbitTemplate = rabbitTemplate;
}
/**
* Clean message properties before sending a message.
*
* @param message
* the message to cleaned up
*/
protected void cleanMessageHeaderProperties(final Message message) {
message.getMessageProperties().getHeaders().remove(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME);
}
/**
* Is needed to convert a incoming message to is originally object type.
*
@@ -68,7 +58,7 @@ public class BaseAmqpService {
return (T) rabbitTemplate.getMessageConverter().fromMessage(message);
}
private boolean isMessageBodyEmpty(final Message message) {
private static boolean isMessageBodyEmpty(final Message message) {
return message == null || message.getBody() == null || message.getBody().length == 0;
}
@@ -98,8 +88,7 @@ public class BaseAmqpService {
return rabbitTemplate.getMessageConverter();
}
protected final String getStringHeaderKey(final Message message, final String key,
final String errorMessageIfNull) {
protected String getStringHeaderKey(final Message message, final String key, final String errorMessageIfNull) {
final Map<String, Object> header = message.getMessageProperties().getHeaders();
final Object value = header.get(key);
if (value == null) {
@@ -117,4 +106,15 @@ public class BaseAmqpService {
protected RabbitTemplate getRabbitTemplate() {
return rabbitTemplate;
}
/**
* Clean message properties before sending a message.
*
* @param message
* the message to cleaned up
*/
protected void cleanMessageHeaderProperties(final Message message) {
message.getMessageProperties().getHeaders().remove(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME);
}
}

View File

@@ -12,6 +12,7 @@ import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFacto
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.util.ErrorHandler;
/**
* {@link RabbitListenerContainerFactory} that can be configured through
@@ -28,10 +29,13 @@ public class ConfigurableRabbitListenerContainerFactory extends SimpleRabbitList
* for the container factory
* @param amqpProperties
* to configure the container factory
* @param errorHandler
* the error handler which should be use
*/
public ConfigurableRabbitListenerContainerFactory(final AmqpProperties amqpProperties,
final ConnectionFactory rabbitConnectionFactory) {
final ConnectionFactory rabbitConnectionFactory, final ErrorHandler errorHandler) {
this.amqpProperties = amqpProperties;
setErrorHandler(errorHandler);
setDefaultRequeueRejected(true);
setConnectionFactory(rabbitConnectionFactory);
setMissingQueuesFatal(amqpProperties.isMissingQueuesFatal());

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.amqp;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import org.eclipse.hawkbit.util.IpUtil;
@@ -46,7 +47,7 @@ public class DefaultAmqpSenderService implements AmqpSenderService {
final String correlationId = UUID.randomUUID().toString();
final String exchange = extractExchange(replyTo);
message.getMessageProperties().setCorrelationId(correlationId.getBytes());
message.getMessageProperties().setCorrelationId(correlationId.getBytes(StandardCharsets.UTF_8));
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Sending message {} to exchange {} with correlationId {}", message, exchange, correlationId);

View File

@@ -114,7 +114,7 @@ public class AmqpControllerAuthenticationTest {
@Description("Tests authentication manager without principal")
public void testAuthenticationeBadCredantialsWithoutPricipal() {
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
FileResource.createFileResourceBySha1("12345"));
try {
authenticationManager.doAuthenticate(securityToken);
fail("BadCredentialsException was excepeted since principal was missing");
@@ -128,7 +128,7 @@ public class AmqpControllerAuthenticationTest {
@Description("Tests authentication manager without wrong credential")
public void testAuthenticationBadCredantialsWithWrongCredential() {
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
FileResource.createFileResourceBySha1("12345"));
when(tenantConfigurationManagement.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE);
@@ -146,7 +146,7 @@ public class AmqpControllerAuthenticationTest {
@Description("Tests authentication successfull")
public void testSuccessfullAuthentication() {
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
FileResource.createFileResourceBySha1("12345"));
when(tenantConfigurationManagement.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE);
@@ -161,7 +161,7 @@ public class AmqpControllerAuthenticationTest {
final MessageProperties messageProperties = createMessageProperties(null);
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
FileResource.createFileResourceBySha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties);
@@ -179,7 +179,7 @@ public class AmqpControllerAuthenticationTest {
public void testAuthenticationMessageBadCredantialsWithWrongCredential() {
final MessageProperties messageProperties = createMessageProperties(null);
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
FileResource.createFileResourceBySha1("12345"));
when(tenantConfigurationManagement.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE);
@@ -201,7 +201,7 @@ public class AmqpControllerAuthenticationTest {
public void testSuccessfullMessageAuthentication() {
final MessageProperties messageProperties = createMessageProperties(null);
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
FileResource.createFileResourceBySha1("12345"));
when(tenantConfigurationManagement.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE);

View File

@@ -279,7 +279,8 @@ public class AmqpMessageHandlerServiceTest {
@Description("Tests that an download request is denied for an artifact which does not exists")
public void authenticationRequestDeniedForArtifactWhichDoesNotExists() {
final MessageProperties messageProperties = createMessageProperties(null);
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", FileResource.sha1("12345"));
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123",
FileResource.createFileResourceBySha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties);
@@ -297,7 +298,8 @@ public class AmqpMessageHandlerServiceTest {
@Description("Tests that an download request is denied for an artifact which is not assigned to the requested target")
public void authenticationRequestDeniedForArtifactWhichIsNotAssignedToTarget() {
final MessageProperties messageProperties = createMessageProperties(null);
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", FileResource.sha1("12345"));
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123",
FileResource.createFileResourceBySha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties);
@@ -320,7 +322,8 @@ public class AmqpMessageHandlerServiceTest {
@Description("Tests that an download request is allowed for an artifact which exists and assigned to the requested target")
public void authenticationRequestAllowedForArtifactWhichExistsAndAssignedToTarget() throws MalformedURLException {
final MessageProperties messageProperties = createMessageProperties(null);
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", FileResource.sha1("12345"));
final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123",
FileResource.createFileResourceBySha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties);

View File

@@ -35,8 +35,8 @@ import ru.yandex.qatools.allure.annotations.Stories;
org.eclipse.hawkbit.RepositoryApplicationConfiguration.class })
public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTestWithMongoDB {
private static final String HTTPS_LOCALHOST = "https://localhost:8080/";
private static final String HTTP_LOCALHOST = "http://localhost:8080/";
private static final String HTTPS_LOCALHOST = "https://localhost/";
private static final String HTTP_LOCALHOST = "http://localhost/";
@Autowired
private ArtifactUrlHandler urlHandlerProperties;

View File

@@ -135,7 +135,7 @@ public class TenantSecurityToken {
* the SHA1 key of the file to obtain
* @return the {@link FileResource} with SHA1 key set
*/
public static FileResource sha1(final String sha1) {
public static FileResource createFileResourceBySha1(final String sha1) {
final FileResource resource = new FileResource();
resource.sha1 = sha1;
return resource;
@@ -148,7 +148,7 @@ public class TenantSecurityToken {
* the filename of the file to obtain
* @return the {@link FileResource} with filename set
*/
public static FileResource filename(final String filename) {
public static FileResource createFileResourceByFilename(final String filename) {
final FileResource resource = new FileResource();
resource.filename = filename;
return resource;

View File

@@ -47,7 +47,7 @@ import com.google.common.collect.UnmodifiableIterator;
*/
public abstract class AbstractHttpControllerAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractHttpControllerAuthenticationFilter.class);
private static final Logger LOG = LoggerFactory.getLogger(AbstractHttpControllerAuthenticationFilter.class);
private static final String TENANT_PLACE_HOLDER = "tenant";
private static final String CONTROLLER_ID_PLACE_HOLDER = "controllerId";
@@ -73,10 +73,12 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
/**
* Constructor for sub-classes.
*
* @param systemManagement
* the system management service
* @param tenantConfigurationManagement
* the tenant configuration service
* @param tenantAware
* the tenant aware service
* @param systemSecurityContext
* the system secruity context
*/
public AbstractHttpControllerAuthenticationFilter(final TenantConfigurationManagement tenantConfigurationManagement,
final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) {
@@ -136,28 +138,28 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
final String requestURI = request.getRequestURI();
if (pathExtractor.match(request.getContextPath() + CONTROLLER_REQUEST_ANT_PATTERN, requestURI)) {
LOGGER.debug("retrieving principal from URI request {}", requestURI);
LOG.debug("retrieving principal from URI request {}", requestURI);
final Map<String, String> extractUriTemplateVariables = pathExtractor
.extractUriTemplateVariables(request.getContextPath() + CONTROLLER_REQUEST_ANT_PATTERN, requestURI);
final String controllerId = extractUriTemplateVariables.get(CONTROLLER_ID_PLACE_HOLDER);
final String tenant = extractUriTemplateVariables.get(TENANT_PLACE_HOLDER);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Parsed tenant {} and controllerId {} from path request {}", tenant, controllerId,
if (LOG.isTraceEnabled()) {
LOG.trace("Parsed tenant {} and controllerId {} from path request {}", tenant, controllerId,
requestURI);
}
return createTenantSecruityTokenVariables(request, tenant, controllerId);
} else if (pathExtractor.match(request.getContextPath() + CONTROLLER_DL_REQUEST_ANT_PATTERN, requestURI)) {
LOGGER.debug("retrieving path variables from URI request {}", requestURI);
LOG.debug("retrieving path variables from URI request {}", requestURI);
final Map<String, String> extractUriTemplateVariables = pathExtractor.extractUriTemplateVariables(
request.getContextPath() + CONTROLLER_DL_REQUEST_ANT_PATTERN, requestURI);
final String tenant = extractUriTemplateVariables.get(TENANT_PLACE_HOLDER);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Parsed tenant {} from path request {}", tenant, requestURI);
if (LOG.isTraceEnabled()) {
LOG.trace("Parsed tenant {} from path request {}", tenant, requestURI);
}
return createTenantSecruityTokenVariables(request, tenant, "anonymous");
} else {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("request {} does not match the path pattern {}, request gets ignored", requestURI,
if (LOG.isTraceEnabled()) {
LOG.trace("request {} does not match the path pattern {}, request gets ignored", requestURI,
CONTROLLER_REQUEST_ANT_PATTERN);
}
return null;
@@ -166,7 +168,8 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
private TenantSecurityToken createTenantSecruityTokenVariables(final HttpServletRequest request,
final String tenant, final String controllerId) {
final TenantSecurityToken secruityToken = new TenantSecurityToken(tenant, controllerId, FileResource.sha1(""));
final TenantSecurityToken secruityToken = new TenantSecurityToken(tenant, controllerId,
FileResource.createFileResourceBySha1(""));
final UnmodifiableIterator<String> forEnumeration = Iterators.forEnumeration(request.getHeaderNames());
forEnumeration.forEachRemaining(header -> secruityToken.getHeaders().put(header, request.getHeader(header)));
return secruityToken;

View File

@@ -22,15 +22,11 @@ import org.springframework.util.AntPathMatcher;
* An {@link AuthenticationDetailsSource} implementation which retrieves the
* tenant from a request pattern {@link #TENANT_AWARE_CONTROLLER_PATTERN} and
* stores the retrieved tenant in the {@link TenantAwareAuthenticationDetails}.
*
*
*/
public class ControllerTenantAwareAuthenticationDetailsSource
implements AuthenticationDetailsSource<HttpServletRequest, TenantAwareAuthenticationDetails> {
/**
*
*/
private static final String TENANT_AWARE_CONTROLLER_PATTERN = "/{tenant}/controller/**";
private static final Logger LOGGER = LoggerFactory
.getLogger(ControllerTenantAwareAuthenticationDetailsSource.class);
@@ -38,19 +34,12 @@ public class ControllerTenantAwareAuthenticationDetailsSource
private final AntPathMatcher pathExtractor;
/**
*
*/
* Constructor.
*/
public ControllerTenantAwareAuthenticationDetailsSource() {
pathExtractor = new AntPathMatcher();
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.authentication.AuthenticationDetailsSource#
* buildDetails(java. lang.Object)
*/
@Override
public TenantAwareAuthenticationDetails buildDetails(final HttpServletRequest request) {
return new TenantAwareWebAuthenticationDetails(getTenantFromRequestUri(request), request.getRemoteAddr(), true);

View File

@@ -28,7 +28,7 @@ import org.springframework.security.web.authentication.preauth.AbstractPreAuthen
public class HttpDownloadAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
public static final String REQUEST_ID_REGEX_PATTERN = ".*\\/downloadId\\/.*";
private static final Logger LOGGER = LoggerFactory.getLogger(HttpDownloadAuthenticationFilter.class);
private static final Logger LOG = LoggerFactory.getLogger(HttpDownloadAuthenticationFilter.class);
private final Pattern pattern;
private final Cache cache;
@@ -50,7 +50,7 @@ public class HttpDownloadAuthenticationFilter extends AbstractPreAuthenticatedPr
if (!matcher.matches()) {
return null;
}
LOGGER.debug("retrieving id from URI request {}", requestURI);
LOG.debug("retrieving id from URI request {}", requestURI);
final String[] groups = requestURI.split("\\/");
final String id = groups[groups.length - 1];
if (id == null) {

View File

@@ -27,6 +27,7 @@ public class MgmtArtifactHash {
* Default constructor.
*/
public MgmtArtifactHash() {
// used for jackson to instantiate
}
/**

View File

@@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
*
*/
@RequestMapping(MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING)
@FunctionalInterface
public interface MgmtDownloadArtifactRestApi {
/**

View File

@@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
*
*/
@RequestMapping(MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE)
@FunctionalInterface
public interface MgmtDownloadRestApi {
/**

View File

@@ -39,7 +39,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -72,15 +72,15 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
@Autowired
private SystemManagement systemManagement;
@Autowired
private TenantAware currentTenant;
@Autowired
private EntityFactory entityFactory;
@Autowired
private DistributionSetManagement distributionSetManagement;
@Autowired
private SystemSecurityContext systemSecurityContext;
@Override
public ResponseEntity<PagedList<MgmtDistributionSet>> getDistributionSets(
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
@@ -119,8 +119,9 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
LOG.debug("creating {} distribution sets", sets.size());
// set default Ds type if ds type is null
sets.stream().filter(ds -> ds.getType() == null).forEach(ds -> ds.setType(this.systemManagement
.getTenantMetadata(this.currentTenant.getCurrentTenant()).getDefaultDsType().getKey()));
final String defaultDsKey = systemSecurityContext
.runAsSystem(() -> this.systemManagement.getTenantMetadata().getDefaultDsType().getKey());
sets.stream().filter(ds -> ds.getType() == null).forEach(ds -> ds.setType(defaultDsKey));
final Iterable<DistributionSet> createdDSets = this.distributionSetManagement
.createDistributionSets(MgmtDistributionSetMapper.dsFromRequest(sets, this.softwareManagement,

View File

@@ -15,6 +15,7 @@ import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.cache.CacheConstants;
import org.eclipse.hawkbit.cache.DownloadArtifactCache;
import org.eclipse.hawkbit.cache.DownloadType;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadRestApi;
import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder;
import org.slf4j.Logger;
@@ -73,14 +74,11 @@ public class MgmtDownloadResource implements MgmtDownloadRestApi {
final DownloadArtifactCache artifactCache = (DownloadArtifactCache) cacheWrapper.get();
DbArtifact artifact = null;
switch (artifactCache.getDownloadType()) {
case BY_SHA1:
artifact = artifactRepository.getArtifactBySha1(artifactCache.getId());
break;
default:
if (DownloadType.BY_SHA1.equals(artifactCache.getDownloadType())) {
artifact = artifactRepository.getArtifactBySha1(artifactCache.getId());
} else {
LOGGER.warn("Download Type {} not supported", artifactCache.getDownloadType());
break;
}
if (artifact == null) {

View File

@@ -23,7 +23,7 @@ import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
* A mapper which maps repository model to RESTful model representation and
* back.
*/
public class MgmtSystemMapper {
public final class MgmtSystemMapper {
private MgmtSystemMapper() {
// Utility class
@@ -51,6 +51,8 @@ public class MgmtSystemMapper {
* maps a TenantConfigurationValue from the repository model to a
* MgmtSystemTenantConfigurationValue, the RESTful model.
*
* @param key
* the key
* @param repoConfValue
* configuration value as repository model
* @return configuration value as RESTful model

View File

@@ -9,16 +9,16 @@
-->
<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>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-repository-api</artifactId>
<name>hawkBit :: Repository API</name>
<dependencies>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-repository-api</artifactId>
<name>hawkBit :: Repository API</name>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-security-core</artifactId>
@@ -36,14 +36,33 @@
<groupId>cz.jirutka.rsql</groupId>
<artifactId>rsql-parser</artifactId>
</dependency>
<dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<!-- Optional -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- TEST -->
<dependency>
<groupId>ru.yandex.qatools.allure</groupId>
<artifactId>allure-junit-adaptor</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -183,6 +183,8 @@ public interface ControllerManagement {
* @return the security context of the target, in case no target exists for
* the given controllerId {@code null} is returned
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_READ_TARGET_SEC_TOKEN)
String getSecurityTokenByControllerId(@NotEmpty String controllerId);
/**

View File

@@ -24,6 +24,7 @@ import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldExc
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetFilter;
import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult;
@@ -32,7 +33,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -44,9 +44,6 @@ import org.springframework.security.access.prepost.PreAuthorize;
*/
public interface DistributionSetManagement {
// TODO rename/document the whole with details thing (document what the
// details are and maybe find a better name, e.g. with dependencies?)
/**
* Assigns {@link SoftwareModule} to existing {@link DistributionSet}.
*
@@ -284,6 +281,16 @@ public interface DistributionSetManagement {
Page<DistributionSetMetadata> findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId,
@NotNull Pageable pageable);
/**
* Finds all meta data by the given distribution set id.
*
* @param distributionSetId
* the distribution set id to retrieve the meta data from
* @return list of distributionSetMetadata for a given distribution set Id.
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
List<DistributionSetMetadata> findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId);
/**
* finds all meta data by the given distribution set id.
*
@@ -320,7 +327,6 @@ public interface DistributionSetManagement {
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
List<DistributionSet> findDistributionSetsAll(Collection<Long> dist);
// TODO discuss: use enum instead of the true,false,null switch ?
/**
* finds all {@link DistributionSet}s.
*

View File

@@ -340,6 +340,7 @@ public interface SoftwareManagement {
* to search for
* @return {@link List} of found {@link SoftwareModule}s
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
List<SoftwareModule> findSoftwareModulesById(@NotEmpty Collection<Long> ids);
/**
@@ -482,5 +483,23 @@ public interface SoftwareManagement {
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
SoftwareModuleType updateSoftwareModuleType(@NotNull SoftwareModuleType sm);
/**
* Finds all meta data by the given software module id.
*
* @param softwareModuleId
* the software module id to retrieve the meta data from
*
* @throws RSQLParameterUnsupportedFieldException
* if a field in the RSQL string is used but not provided by the
* given {@code fieldNameProvider}
* @throws RSQLParameterSyntaxException
* if the RSQL syntax is wrong
* @return result of all meta data entries for a given software
* module id.
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
List<SoftwareModuleMetadata> findSoftwareModuleMetadataBySoftwareModuleId(Long softwareModuleId);
}

View File

@@ -61,6 +61,9 @@ public interface SystemManagement {
/**
* @return {@link TenantMetaData} of {@link TenantAware#getCurrentTenant()}
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
TenantMetaData getTenantMetadata();
/**
@@ -77,6 +80,7 @@ public interface SystemManagement {
* to retrieve data for
* @return {@link TenantMetaData} of given tenant
*/
@PreAuthorize(SpringEvalExpressions.IS_SYSTEM_CODE)
TenantMetaData getTenantMetadata(@NotNull String tenant);
/**
@@ -86,6 +90,7 @@ public interface SystemManagement {
* to update
* @return updated {@link TenantMetaData} entity
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
TenantMetaData updateTenantMetadata(@NotNull TenantMetaData metaData);
}
}

View File

@@ -0,0 +1,28 @@
/**
* 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.repository.eventbus.event;
import org.eclipse.hawkbit.repository.model.DistributionSet;
/**
* Defines the {@link AbstractBaseEntityEvent} of creating a new {@link DistributionSet}.
*
*/
public class DistributionCreatedEvent extends AbstractBaseEntityEvent<DistributionSet> {
private static final long serialVersionUID = 1L;
/**
* @param distributionSet
* the distributionSet which has been created
*/
public DistributionCreatedEvent(final DistributionSet distributionSet) {
super(distributionSet);
}
}

View File

@@ -0,0 +1,36 @@
/**
* 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.repository.eventbus.event;
import org.eclipse.hawkbit.eventbus.event.AbstractDistributedEvent;
import org.eclipse.hawkbit.repository.model.DistributionSet;
/**
* Defines the {@link AbstractDistributedEvent} for deletion of
* {@link DistributionSet}.
*/
public class DistributionDeletedEvent extends AbstractDistributedEvent {
private static final long serialVersionUID = -3308850381757843098L;
private final Long distributionId;
/**
* @param tenant
* the tenant for this event
* @param distributionId
* the ID of the distribution set which has been deleted
*/
public DistributionDeletedEvent(final String tenant, final Long distributionId) {
super(-1, tenant);
this.distributionId = distributionId;
}
public Long getDistributionSetId() {
return distributionId;
}
}

View File

@@ -0,0 +1,29 @@
/**
* 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.repository.eventbus.event;
import org.eclipse.hawkbit.repository.model.DistributionSet;
/**
* Defines the {@link AbstractBaseEntityEvent} for update a {@link DistributionSet}.
*
*/
public class DistributionSetUpdateEvent extends AbstractBaseEntityEvent<DistributionSet> {
private static final long serialVersionUID = 1L;
/**
* Constructor
* @param ds Distribution Set
*/
public DistributionSetUpdateEvent(final DistributionSet ds) {
super(ds);
}
}

View File

@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.repository.eventbus.event;
import org.eclipse.hawkbit.eventbus.event.AbstractEvent;
import org.eclipse.hawkbit.eventbus.event.DefaultEvent;
/**
* Event declaration for the UI to notify the UI that a rollout has been
@@ -17,7 +17,7 @@ import org.eclipse.hawkbit.eventbus.event.AbstractEvent;
* @author Michael Hirsch
*
*/
public class RolloutChangeEvent extends AbstractEvent {
public class RolloutChangeEvent extends DefaultEvent {
private final Long rolloutId;

View File

@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.repository.eventbus.event;
import org.eclipse.hawkbit.eventbus.event.AbstractEvent;
import org.eclipse.hawkbit.eventbus.event.DefaultEvent;
/**
* Event declaration for the UI to notify the UI that a rollout has been
@@ -17,7 +17,7 @@ import org.eclipse.hawkbit.eventbus.event.AbstractEvent;
* @author Michael Hirsch
*
*/
public class RolloutGroupChangeEvent extends AbstractEvent {
public class RolloutGroupChangeEvent extends DefaultEvent {
private final Long rolloutId;
private final Long rolloutGroupId;

View File

@@ -11,14 +11,14 @@ package org.eclipse.hawkbit.repository.eventbus.event;
import java.net.URI;
import java.util.Collection;
import org.eclipse.hawkbit.eventbus.event.AbstractEvent;
import org.eclipse.hawkbit.eventbus.event.DefaultEvent;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
/**
* Event that gets sent when a distribution set gets assigned to a target.
*
*/
public class TargetAssignDistributionSetEvent extends AbstractEvent {
public class TargetAssignDistributionSetEvent extends DefaultEvent {
private final Collection<SoftwareModule> softwareModules;
private final String controllerId;

View File

@@ -0,0 +1,41 @@
/**
* 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.repository.eventbus.event;
import org.eclipse.hawkbit.eventbus.event.AbstractDistributedEvent;
import org.eclipse.hawkbit.repository.model.Target;
/**
*
* Defines the {@link AbstractBaseEntityEvent} of deleting a {@link Target}.
*/
public class TargetDeletedEvent extends AbstractDistributedEvent {
private static final long serialVersionUID = 1L;
private final long targetId;
/**
* @param tenant
* the tenant for this event
* @param targetId
* the ID of the target which has been deleted
*/
public TargetDeletedEvent(final String tenant, final long targetId) {
super(-1, tenant);
this.targetId = targetId;
}
/**
* @return the targetId
*/
public long getTargetId() {
return targetId;
}
}

View File

@@ -0,0 +1,31 @@
/**
* 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.repository.eventbus.event;
import org.eclipse.hawkbit.repository.model.Target;
/**
* Defines the {@link AbstractBaseEntityEvent} of updating a {@link Target}.
*
*/
public class TargetUpdatedEvent extends AbstractBaseEntityEvent<Target> {
private static final long serialVersionUID = 5665118668865832477L;
/**
* Constructor
*
* @param baseEntity
* Target entity
*/
public TargetUpdatedEvent(final Target baseEntity) {
super(baseEntity);
}
}

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Thrown if artifact deletion failed.
@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public final class ArtifactDeleteFailedException extends SpServerRtException {
public final class ArtifactDeleteFailedException extends AbstractServerRtException {
/**
*
*/

View File

@@ -9,14 +9,14 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
*
*
*
*/
public final class ArtifactUploadFailedException extends SpServerRtException {
public final class ArtifactUploadFailedException extends AbstractServerRtException {
/**
*

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Thrown if cancelation of actions is performened where the action is not
@@ -19,7 +19,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public final class CancelActionNotAllowedException extends SpServerRtException {
public final class CancelActionNotAllowedException extends AbstractServerRtException {
/**
*
*/

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* {@link ConcurrentModificationException} is thrown when a given entity in's
@@ -19,7 +19,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public class ConcurrentModificationException extends SpServerRtException {
public class ConcurrentModificationException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_CONCURRENT_MODIFICATION;

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Thrown if DS creation failed.
@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public final class DistributionSetCreationFailedMissingMandatoryModuleException extends SpServerRtException {
public final class DistributionSetCreationFailedMissingMandatoryModuleException extends AbstractServerRtException {
/**
*
*/

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
@@ -21,7 +21,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetType;
*
*
*/
public class DistributionSetTypeUndefinedException extends SpServerRtException {
public class DistributionSetTypeUndefinedException extends AbstractServerRtException {
/**
*
*/

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* the {@link EntityAlreadyExistsException} is thrown when a entity is tried to
@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public class EntityAlreadyExistsException extends SpServerRtException {
public class EntityAlreadyExistsException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_ENTITY_ALRREADY_EXISTS;

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* The {@link EntityLockedException} is thrown when an entity has been locked by
@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public class EntityLockedException extends SpServerRtException {
public class EntityLockedException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_ENTITY_LOCKED;

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* the {@link EntityNotFoundException} is thrown when a entity is tried find but
@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public class EntityNotFoundException extends SpServerRtException {
public class EntityNotFoundException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_ENTITY_NOT_EXISTS;

View File

@@ -9,13 +9,13 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* the {@link EntityReadOnlyException} is thrown when a entity is in read only
* mode and a user tries to change it.
*/
public class EntityReadOnlyException extends SpServerRtException {
public class EntityReadOnlyException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_ENTITY_READ_ONLY;

View File

@@ -9,14 +9,14 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Thrown when force quitting an actions is not allowed. e.g. the action is not
* active or it is not canceled before.
*
*/
public final class ForceQuitActionNotAllowedException extends SpServerRtException {
public final class ForceQuitActionNotAllowedException extends AbstractServerRtException {
/**
*
*/

View File

@@ -9,14 +9,14 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
*
*
*
*/
public final class GridFSDBFileNotFoundException extends SpServerRtException {
public final class GridFSDBFileNotFoundException extends AbstractServerRtException {
/**
*

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Thrown if a distribution set is assigned to a a target that is incomplete
@@ -19,7 +19,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public final class IncompleteDistributionSetException extends SpServerRtException {
public final class IncompleteDistributionSetException extends AbstractServerRtException {
/**
*
*/

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Exception which is thrown in case the current security context object does
@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public class InsufficientPermissionException extends SpServerRtException {
public class InsufficientPermissionException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Thrown if MD5 checksum check fails.
@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public class InvalidMD5HashException extends SpServerRtException {
public class InvalidMD5HashException extends AbstractServerRtException {
/**
*
*/

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Thrown if SHA1 checksum check fails.
@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public class InvalidSHA1HashException extends SpServerRtException {
public class InvalidSHA1HashException extends AbstractServerRtException {
/**
*
*/

View File

@@ -9,12 +9,12 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Exception which is thrown when trying to set an invalid target address.
*/
public class InvalidTargetAddressException extends SpServerRtException {
public class InvalidTargetAddressException extends AbstractServerRtException {
/**
*

View File

@@ -9,13 +9,13 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Thrown if a multi part exception occurred.
*
*/
public final class MultiPartFileUploadException extends SpServerRtException {
public final class MultiPartFileUploadException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Exception used by the REST API in case of RSQL search filter query.
@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public class RSQLParameterSyntaxException extends SpServerRtException {
public class RSQLParameterSyntaxException extends AbstractServerRtException {
/**
*

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* Exception used by the REST API in case of invalid field name in the rsql
@@ -19,7 +19,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public class RSQLParameterUnsupportedFieldException extends SpServerRtException {
public class RSQLParameterUnsupportedFieldException extends AbstractServerRtException {
/**
*

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* the {@link RolloutIllegalStateException} is thrown when a rollout is changing
@@ -17,7 +17,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
* rollout, or trying to resume a already finished rollout.
*
*/
public class RolloutIllegalStateException extends SpServerRtException {
public class RolloutIllegalStateException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_ROLLOUT_ILLEGAL_STATE;

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.exception;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.exception.SpServerRtException;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
/**
* the {@link TenantNotExistException} is thrown when e.g. a controller tries to
@@ -20,7 +20,7 @@ import org.eclipse.hawkbit.exception.SpServerRtException;
*
*
*/
public class TenantNotExistException extends SpServerRtException {
public class TenantNotExistException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_TENANT_NOT_EXISTS;

Some files were not shown because too many files have changed in this diff Show More