Initial check in accordance with Parallel IP
This commit is contained in:
15
hawkbit-repository/src/fbExcludeFilter.xml
Executable file
15
hawkbit-repository/src/fbExcludeFilter.xml
Executable file
@@ -0,0 +1,15 @@
|
||||
<!--
|
||||
|
||||
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
|
||||
|
||||
-->
|
||||
<FindBugsFilter>
|
||||
<Match>
|
||||
<Method name="~_persistence_[sg]et.*" />
|
||||
</Match>
|
||||
</FindBugsFilter>
|
||||
36
hawkbit-repository/src/main/java/org/eclipse/hawkbit/Constants.java
Executable file
36
hawkbit-repository/src/main/java/org/eclipse/hawkbit/Constants.java
Executable 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;
|
||||
|
||||
/**
|
||||
* A constant class which holds only static constants used within the SP server.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class Constants {
|
||||
|
||||
/**
|
||||
* Defines the maximum entries for SQL in-statement. Many database have
|
||||
* limit of elements within an SQL in-statement, e.g. Oracle with maximum
|
||||
* 1000 elements. So everywhere we are using in-statements in our SQL
|
||||
* queries we need to split these elements for the in-statements by this
|
||||
* number.
|
||||
*/
|
||||
public static final int MAX_ENTRIES_IN_STATEMENT = 999;
|
||||
|
||||
/**
|
||||
* constant class only private constructor.
|
||||
*/
|
||||
private Constants() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.transaction.Transaction;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.orm.jpa.EntityManagerHolder;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
* {@link JpaTransactionManager} that sets the
|
||||
* {@link TenantAware#getCurrentTenant()} in the eclipselink session. This has
|
||||
* to be done in eclipselink after a {@link Transaction} has been started.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class MultiTenantJpaTransactionManager extends JpaTransactionManager {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Autowired
|
||||
private transient TenantAware tenantAware;
|
||||
|
||||
@Override
|
||||
protected void doBegin(final Object transaction, final TransactionDefinition definition) {
|
||||
super.doBegin(transaction, definition);
|
||||
|
||||
final EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager
|
||||
.getResource(getEntityManagerFactory());
|
||||
final EntityManager em = emHolder.getEntityManager();
|
||||
|
||||
if (!definition.getName().startsWith(SystemManagement.class.getCanonicalName() + ".findTenants")
|
||||
&& !definition.getName().startsWith(SystemManagement.class.getCanonicalName() + ".deleteTenant")
|
||||
&& !definition.getName()
|
||||
.startsWith(SystemManagement.class.getCanonicalName() + ".currentTenantKeyGenerator")) {
|
||||
|
||||
final String currentTenant = tenantAware.getCurrentTenant();
|
||||
if (currentTenant == null) {
|
||||
throw new TenantNotExistException("Tenant Unknown. Canceling transaction.");
|
||||
}
|
||||
|
||||
em.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, currentTenant.toUpperCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.aspects.SpExceptionMappingAspect;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.model.helper.CacheManagerHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.PollConfigurationHelper;
|
||||
import org.eclipse.hawkbit.repository.model.helper.SecurityTokenGeneratorHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.TenantAwareHolder;
|
||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
|
||||
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
|
||||
/**
|
||||
* General configuration for the SP Repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@EnableJpaRepositories(basePackages = { "org.eclipse.hawkbit.repository" })
|
||||
@EnableTransactionManagement
|
||||
@EnableJpaAuditing
|
||||
@EnableAspectJAutoProxy
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration
|
||||
public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* @return simple default {@link AsyncUncaughtExceptionHandler}
|
||||
* implementation
|
||||
* @Bean public SimpleAsyncUncaughtExceptionHandler
|
||||
* simpleAsyncUncaughtExceptionHandler() { return new
|
||||
* SimpleAsyncUncaughtExceptionHandler(); }
|
||||
*
|
||||
* /**
|
||||
* @return the {@link PollConfigurationHelper} singleton bean which holds
|
||||
* the polling and polling overdue configuration and make it
|
||||
* accessible in beans which cannot not be autowired or retrieve
|
||||
* environment variables due {@link EnvironmentAware} interface.
|
||||
*/
|
||||
@Bean
|
||||
public PollConfigurationHelper pollConfigurationHelper() {
|
||||
return PollConfigurationHelper.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link SystemManagementHolder} singleton bean which holds the
|
||||
* current {@link SystemManagement} service and make it accessible
|
||||
* in beans which cannot access the service directly, e.g. JPA
|
||||
* entities.
|
||||
*/
|
||||
@Bean
|
||||
public SystemManagementHolder systemManagementHolder() {
|
||||
return SystemManagementHolder.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link TenantAwareHolder} singleton bean which holds the
|
||||
* current {@link TenantAware} service and make it accessible in
|
||||
* beans which cannot access the service directly, e.g. JPA
|
||||
* entities.
|
||||
*/
|
||||
@Bean
|
||||
public TenantAwareHolder tenantAwareHolder() {
|
||||
return TenantAwareHolder.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link SecurityTokenGeneratorHolder} singleton bean which
|
||||
* holds the current {@link SecurityTokenGenerator} service and make
|
||||
* it accessible in beans which cannot access the service via
|
||||
* injection
|
||||
*/
|
||||
@Bean
|
||||
public SecurityTokenGeneratorHolder securityTokenGeneratorHolder() {
|
||||
return SecurityTokenGeneratorHolder.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the singleton instance of the {@link CacheManagerHolder}
|
||||
*/
|
||||
@Bean
|
||||
public CacheManagerHolder cacheManagerHolder() {
|
||||
return CacheManagerHolder.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the validation processor bean.
|
||||
*
|
||||
* @return the {@link MethodValidationPostProcessor}
|
||||
*/
|
||||
@Bean
|
||||
public MethodValidationPostProcessor methodValidationPostProcessor() {
|
||||
return new MethodValidationPostProcessor();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link SpExceptionMappingAspect} aspect bean
|
||||
*/
|
||||
@Bean
|
||||
public SpExceptionMappingAspect createRepositoryExceptionHandlerAdvice() {
|
||||
return new SpExceptionMappingAspect();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration#
|
||||
* createJpaVendorAdapter()
|
||||
*/
|
||||
@Override
|
||||
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
|
||||
return new EclipseLinkJpaVendorAdapter();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration#
|
||||
* getVendorProperties()
|
||||
*/
|
||||
@Override
|
||||
protected Map<String, Object> getVendorProperties() {
|
||||
|
||||
final Map<String, Object> properties = new HashMap<String, Object>();
|
||||
// Turn off dynamic weaving to disable LTW lookup in static weaving mode
|
||||
properties.put("eclipselink.weaving", "false");
|
||||
// needed for reports
|
||||
properties.put("eclipselink.jdbc.allow-native-sql-queries", "true");
|
||||
// flyway
|
||||
properties.put("eclipselink.ddl-generation", "none");
|
||||
|
||||
properties.put("eclipselink.persistence-context.flush-mode", "auto");
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link MultiTenantJpaTransactionManager} bean.
|
||||
*
|
||||
* @see org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration#transactionManager()
|
||||
* @return a new {@link PlatformTransactionManager}
|
||||
*/
|
||||
@Override
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager() {
|
||||
return new MultiTenantJpaTransactionManager();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 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.aspects;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.eclipse.hawkbit.exception.GenericSpServerException;
|
||||
import org.eclipse.hawkbit.repository.exception.ConcurrentModificationException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
|
||||
/**
|
||||
* {@link Aspect} catches persistence exceptions and wraps them to custom
|
||||
* specific exceptions Additionally it checks and prevents access to certain
|
||||
* packages. Logging aspect which logs the call stack
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Aspect
|
||||
public class SpExceptionMappingAspect implements Ordered {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SpExceptionMappingAspect.class);
|
||||
|
||||
private static final Map<String, String> EXCEPTION_MAPPING = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* this is required to enable a certain order of exception and to select the
|
||||
* most specific mappable exception according to the type hierarchy of the
|
||||
* exception.
|
||||
*/
|
||||
private static final List<Class<?>> MAPPED_EXCEPTION_ORDER = new ArrayList<Class<?>>();
|
||||
|
||||
static {
|
||||
MAPPED_EXCEPTION_ORDER.add(DuplicateKeyException.class);
|
||||
MAPPED_EXCEPTION_ORDER.add(DataIntegrityViolationException.class);
|
||||
MAPPED_EXCEPTION_ORDER.add(ConcurrencyFailureException.class);
|
||||
MAPPED_EXCEPTION_ORDER.add(AccessDeniedException.class);
|
||||
|
||||
EXCEPTION_MAPPING.put(DuplicateKeyException.class.getName(), EntityAlreadyExistsException.class.getName());
|
||||
|
||||
EXCEPTION_MAPPING.put(ConcurrencyFailureException.class.getName(),
|
||||
ConcurrentModificationException.class.getName());
|
||||
EXCEPTION_MAPPING.put(AccessDeniedException.class.getName(), InsufficientPermissionException.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* catch exceptions of the {@link TransactionManager} and wrap them to
|
||||
* custom exceptions.
|
||||
*
|
||||
* @param ex
|
||||
* the thrown and catched exception
|
||||
* @throws Throwable
|
||||
*/
|
||||
@AfterThrowing(pointcut = "( execution( * org.springframework.transaction..*.*(..)) "
|
||||
+ " || execution( * org.eclipse.hawkbit.repository.*.*(..)) "
|
||||
+ " || execution( * org.eclipse.hawkbit.controller.*.*(..)) "
|
||||
+ " || execution( * org.eclipse.hawkbit.service.*.*(..)) )", throwing = "ex")
|
||||
public void catchAndWrapJpaExceptionsService(final Exception ex) throws Throwable {
|
||||
final Class<? extends Exception> exClass = ex.getClass();
|
||||
Exception newEx = ex;
|
||||
LOG.trace("exception occured", ex);
|
||||
for (final Class<?> mappedEx : MAPPED_EXCEPTION_ORDER) {
|
||||
|
||||
if (mappedEx.isAssignableFrom(exClass)) {
|
||||
if (!EXCEPTION_MAPPING.containsKey(mappedEx.getName())) {
|
||||
LOG.error("there is no mapping configured for exception class {}", mappedEx.getName());
|
||||
newEx = new GenericSpServerException(ex);
|
||||
} else {
|
||||
newEx = (Exception) Class.forName(EXCEPTION_MAPPING.get(mappedEx.getName()))
|
||||
.getConstructor(Throwable.class).newInstance(ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG.trace("mapped exception {} to {}", ex.getClass(), newEx.getClass());
|
||||
throw newEx;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.core.Ordered#getOrder()
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
41
hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheField.java
vendored
Executable file
41
hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheField.java
vendored
Executable 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.cache;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.eclipse.hawkbit.eventbus.CacheFieldEntityListener;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
|
||||
/**
|
||||
* Marks an field within a JPA entity as transient and this field should be
|
||||
* loaded from a configured {@link CacheManager} by using the JPA entity
|
||||
* listeners.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @see CacheFieldEntityListener
|
||||
*/
|
||||
@Target({ FIELD })
|
||||
@Retention(RUNTIME)
|
||||
@Transient
|
||||
public @interface CacheField {
|
||||
|
||||
/**
|
||||
* @return the cache key name for this cacheable field which is used to
|
||||
* store the value.
|
||||
*/
|
||||
String key();
|
||||
|
||||
}
|
||||
54
hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheKeys.java
vendored
Executable file
54
hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheKeys.java
vendored
Executable file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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.cache;
|
||||
|
||||
import org.eclipse.hawkbit.eventbus.CacheFieldEntityListener;
|
||||
|
||||
/**
|
||||
* Constants for cache keys used in multiple classes.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* @see CacheFieldEntityListener
|
||||
* @see CacheWriteNotify
|
||||
* @see CacheField
|
||||
*
|
||||
*/
|
||||
public final class CacheKeys {
|
||||
|
||||
/**
|
||||
* The cache key name for the {@link UpdateActionStatus} download progress
|
||||
* event.
|
||||
*/
|
||||
public static final String DOWNLOAD_PROGRESS_PERCENT = "download.progress.percent";
|
||||
|
||||
/**
|
||||
* utility class only private constructor.
|
||||
*/
|
||||
private CacheKeys() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* calculates the cache key for a specific entity. The cache key must be
|
||||
* different for each different identifiable entity by its ID.
|
||||
*
|
||||
* @param entityId
|
||||
* the ID of the entity to build the specific cache key for this
|
||||
* entity
|
||||
* @param cacheKey
|
||||
* the cache key for the field to be cached
|
||||
* @return the combined cache key based on the given {@code entityId} and
|
||||
* {@code cacheKey}
|
||||
*/
|
||||
public static String entitySpecificCacheKey(final String entityId, final String cacheKey) {
|
||||
return entityId + "." + cacheKey;
|
||||
}
|
||||
}
|
||||
96
hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheWriteNotify.java
vendored
Executable file
96
hawkbit-repository/src/main/java/org/eclipse/hawkbit/cache/CacheWriteNotify.java
vendored
Executable file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* 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.cache;
|
||||
|
||||
import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
/**
|
||||
* An service which combines the functionality for functional use cases to write
|
||||
* into the cache an notify the writing to the cache to the {@link EventBus}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class CacheWriteNotify {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final int DOWNLOAD_PROGRESS_MAX = 100;
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
|
||||
@Autowired
|
||||
private EventBus eventBus;
|
||||
|
||||
@Autowired
|
||||
private TenantAware tenantAware;
|
||||
|
||||
/**
|
||||
* writes the download progress in percentage into the cache
|
||||
* {@link CacheKeys#DOWNLOAD_PROGRESS_PERCENT} and notifies the
|
||||
* {@link EventBus} with a {@link DownloadProgressEvent}.
|
||||
*
|
||||
* @param statusId
|
||||
* the ID of the {@link ActionStatus}
|
||||
* @param progressPercent
|
||||
* the progress in percentage which must be between 0-100
|
||||
*/
|
||||
public void downloadProgressPercent(final long statusId, final int progressPercent) {
|
||||
|
||||
final Cache cache = cacheManager.getCache(Action.class.getName());
|
||||
final String cacheKey = CacheKeys.entitySpecificCacheKey(String.valueOf(statusId),
|
||||
CacheKeys.DOWNLOAD_PROGRESS_PERCENT);
|
||||
if (progressPercent < DOWNLOAD_PROGRESS_MAX) {
|
||||
cache.put(cacheKey, progressPercent);
|
||||
} else {
|
||||
// in case we reached progress 100 delete the cache value again
|
||||
// because otherwise he will
|
||||
// keep there forever
|
||||
cache.evict(cacheKey);
|
||||
}
|
||||
|
||||
eventBus.post(new DownloadProgressEvent(tenantAware.getCurrentTenant(), statusId, progressPercent));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cacheManager
|
||||
* the cacheManager to set
|
||||
*/
|
||||
void setCacheManager(final CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param eventBus
|
||||
* the eventBus to set
|
||||
*/
|
||||
void setEventBus(final EventBus eventBus) {
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tenantAware
|
||||
* the tenantAware to set
|
||||
*/
|
||||
void setTenantAware(final TenantAware tenantAware) {
|
||||
this.tenantAware = tenantAware;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* 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.eventbus;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import javax.persistence.PostLoad;
|
||||
import javax.persistence.PostRemove;
|
||||
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import org.eclipse.hawkbit.cache.CacheField;
|
||||
import org.eclipse.hawkbit.cache.CacheKeys;
|
||||
import org.eclipse.hawkbit.repository.model.helper.CacheManagerHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.Cache.ValueWrapper;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.hateoas.Identifiable;
|
||||
|
||||
/**
|
||||
* An JPA entity listener which enriches the JPA entity fields which are
|
||||
* annotated with {@link CacheField} with values from the {@link CacheManager}.
|
||||
* Only JPA entities which are implementing {@link Identifiable} can be handled
|
||||
* by this entity listener cause the cache keys are calculated with the ID of
|
||||
* the entity.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class CacheFieldEntityListener {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CacheFieldEntityListener.class);
|
||||
|
||||
/**
|
||||
* enriches the JPA entities after loading the entity from the SQL database.
|
||||
*
|
||||
* @param target
|
||||
* the target which has been loaded from the database
|
||||
*/
|
||||
@PostLoad
|
||||
public void postLoad(final Object target) {
|
||||
if (target instanceof Identifiable) {
|
||||
final CacheManager cacheManager = CacheManagerHolder.getInstance().getCacheManager();
|
||||
@SuppressWarnings("rawtypes")
|
||||
final String id = ((Identifiable) target).getId().toString();
|
||||
final Class<? extends Object> type = target.getClass();
|
||||
findCacheFields(type, id, new CacheFieldCallback() {
|
||||
@Override
|
||||
public void fromCache(final Field field, final String cacheKey, final Serializable id)
|
||||
throws IllegalAccessException {
|
||||
final Cache cache = cacheManager.getCache(type.getName());
|
||||
final ValueWrapper valueWrapper = cache
|
||||
.get(CacheKeys.entitySpecificCacheKey(id.toString(), cacheKey));
|
||||
if (valueWrapper != null && valueWrapper.get() != null) {
|
||||
FieldUtils.writeField(field, target, valueWrapper.get(), true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes the associated cache fields from the cache when deleted the
|
||||
* entity from the database.
|
||||
*
|
||||
* @param target
|
||||
* the entity which has been deleted
|
||||
*/
|
||||
@PostRemove
|
||||
public void postDelete(final Object target) {
|
||||
if (target instanceof Identifiable) {
|
||||
final CacheManager cacheManager = CacheManagerHolder.getInstance().getCacheManager();
|
||||
@SuppressWarnings("rawtypes")
|
||||
final String id = ((Identifiable) target).getId().toString();
|
||||
final Class<? extends Object> type = target.getClass();
|
||||
findCacheFields(type, id, new CacheFieldCallback() {
|
||||
@Override
|
||||
public void fromCache(final Field field, final String cacheKey, final Serializable id)
|
||||
throws IllegalAccessException {
|
||||
final Cache cache = cacheManager.getCache(type.getName());
|
||||
cache.evict(CacheKeys.entitySpecificCacheKey(id.toString(), cacheKey));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void findCacheFields(final Class<? extends Object> type, final Serializable id,
|
||||
final CacheFieldCallback callback) {
|
||||
final Field[] declaredFields = type.getDeclaredFields();
|
||||
for (final Field field : declaredFields) {
|
||||
if (field.getAnnotation(CacheField.class) != null) {
|
||||
try {
|
||||
final CacheField annotation = field.getAnnotation(CacheField.class);
|
||||
callback.fromCache(field, annotation.key(), id);
|
||||
} catch (final IllegalAccessException e) {
|
||||
LOGGER.error("cannot access the field {} for the entity {}, ignoring the cacheable field", field,
|
||||
type, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private interface CacheFieldCallback {
|
||||
/**
|
||||
* callback methods which is called by the
|
||||
* {@link CacheFieldEntityListener#findCacheFields(Class, Serializable, CacheFieldCallback)}
|
||||
* in case a field is annotated with {@link CacheField}.
|
||||
*
|
||||
* @param field
|
||||
* the field which is annotaed with {@link CacheField}
|
||||
* @param cacheKey
|
||||
* the configured cache key in the annotation
|
||||
* {@link CacheField#key()}
|
||||
* @param id
|
||||
* the ID of the entity
|
||||
* @throws IllegalAccessException
|
||||
* in case the field cannot be accessed
|
||||
*/
|
||||
void fromCache(final Field field, final String cacheKey, Serializable id) throws IllegalAccessException;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* 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.eventbus;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.eclipse.hawkbit.eventbus.event.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent;
|
||||
import org.eclipse.hawkbit.eventbus.event.TargetInfoUpdateEvent;
|
||||
import org.eclipse.hawkbit.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
/**
|
||||
* An aspect implementation which wraps the necessary repository services for
|
||||
* saving {@link BaseEntity}s to publish create or update events.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
@Aspect
|
||||
public class EntityChangeEventListener {
|
||||
|
||||
@Autowired
|
||||
private EventBus eventBus;
|
||||
|
||||
@Autowired
|
||||
private TenantAware tenantAware;
|
||||
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
/**
|
||||
* In case the a {@link Target} is created a corresponding
|
||||
* {@link TargetInfo} is created as well. We need the {@link TargetInfo}
|
||||
* information in the target created event. So we are listening to the
|
||||
* {@link TargetInfo} creation to indicate if an Target has been created.
|
||||
*
|
||||
* @param joinpoint
|
||||
* the aspect join point
|
||||
* @return the object of the {@link ProceedingJoinPoint#proceed()}
|
||||
* @throws Throwable
|
||||
* in case exception happens in the
|
||||
* {@link ProceedingJoinPoint#proceed()}
|
||||
*/
|
||||
@Around("execution(* org.eclipse.hawkbit.repository.TargetInfoRepository.save(..))")
|
||||
public Object targetCreated(final ProceedingJoinPoint joinpoint) throws Throwable {
|
||||
final boolean isNew = isTargetInfoNew(joinpoint.getArgs()[0]);
|
||||
final Object result = joinpoint.proceed();
|
||||
if (result instanceof TargetInfo) {
|
||||
if (isNew) {
|
||||
// we need to flush here because seems like eclipselink
|
||||
// implementation setting the ID of the target no immediately
|
||||
// otherwise.
|
||||
entityManager.flush();
|
||||
notifyTargetCreated(entityManager.merge(entityManager.merge(((TargetInfo) result).getTarget())));
|
||||
} else {
|
||||
notifyTargetInfoChanged((TargetInfo) result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy method around the delete method of the {@link TargetRepository} to
|
||||
* notify the {@link TargetDeletedEvent} in case targets has been deleted.
|
||||
*
|
||||
* @param joinpoint
|
||||
* the aspect join point
|
||||
* @return the object of the {@link ProceedingJoinPoint#proceed()}
|
||||
* @throws Throwable
|
||||
* in case exception happens in the
|
||||
* {@link ProceedingJoinPoint#proceed()}
|
||||
*/
|
||||
@Around("execution(* org.eclipse.hawkbit.repository.TargetRepository.deleteByIdIn(..))")
|
||||
public Object targetDeletedById(final ProceedingJoinPoint joinpoint) throws Throwable {
|
||||
final String currentTenant = tenantAware.getCurrentTenant();
|
||||
final Object result = joinpoint.proceed();
|
||||
final Collection<Long> targetIds = (Collection<Long>) joinpoint.getArgs()[0];
|
||||
targetIds.forEach(targetId -> notifyTargetDeleted(currentTenant, targetId));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy method around the delete method of the {@link TargetRepository} to
|
||||
* notify the {@link TargetDeletedEvent} in case targets has been deleted.
|
||||
*
|
||||
* @param joinpoint
|
||||
* the aspect join point
|
||||
* @return the object of the {@link ProceedingJoinPoint#proceed()}
|
||||
* @throws Throwable
|
||||
* in case exception happens in the
|
||||
* {@link ProceedingJoinPoint#proceed()}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Around("execution(* org.eclipse.hawkbit.repository.TargetRepository.delete(..))")
|
||||
public Object targetDeleted(final ProceedingJoinPoint joinpoint) throws Throwable {
|
||||
final String currentTenant = tenantAware.getCurrentTenant();
|
||||
final Object result = joinpoint.proceed();
|
||||
final Object param = joinpoint.getArgs()[0];
|
||||
// delete by id
|
||||
if (param instanceof Long) {
|
||||
notifyTargetDeleted(currentTenant, (Long) param);
|
||||
} else if (param instanceof Target) {
|
||||
notifyTargetDeleted(currentTenant, ((Target) param).getId());
|
||||
} else if (param instanceof Iterable) {
|
||||
((Iterable<Target>) param).forEach(target -> notifyTargetDeleted(currentTenant, target.getId()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void notifyTargetCreated(final Target t) {
|
||||
eventBus.post(new TargetCreatedEvent(t));
|
||||
}
|
||||
|
||||
private void notifyTargetInfoChanged(final TargetInfo targetInfo) {
|
||||
eventBus.post(new TargetInfoUpdateEvent(targetInfo));
|
||||
}
|
||||
|
||||
private void notifyTargetDeleted(final String tenant, final Long targetId) {
|
||||
eventBus.post(new TargetDeletedEvent(tenant, targetId));
|
||||
}
|
||||
|
||||
private boolean isTargetInfoNew(final Object targetInfo) {
|
||||
return ((TargetInfo) targetInfo).isNew();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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.eventbus.event;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
|
||||
/**
|
||||
* An abstract definition class for {@link EntityEvent} for {@link BaseEntity}s,
|
||||
* which holds the {@link BaseEntity}.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param <E>
|
||||
* the type of the {@link BaseEntity}
|
||||
*/
|
||||
public abstract class AbstractBaseEntityEvent<E extends BaseEntity> extends AbstractDistributedEvent
|
||||
implements EntityEvent {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final E entity;
|
||||
|
||||
/**
|
||||
* @param baseEntity
|
||||
* the entity which has been created or modified
|
||||
*/
|
||||
public AbstractBaseEntityEvent(final E baseEntity) {
|
||||
super(baseEntity.getOptLockRevision(), baseEntity.getTenant());
|
||||
this.entity = baseEntity;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getEntity()
|
||||
*/
|
||||
@Override
|
||||
public E getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getEntity(java.lang
|
||||
* .Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> T getEntity(final Class<T> entityClass) {
|
||||
return entityClass.cast(entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getTenant()
|
||||
*/
|
||||
@Override
|
||||
public String getTenant() {
|
||||
return entity.getTenant();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 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.eventbus.event;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
|
||||
/**
|
||||
* Event that gets sent when a distribution set gets assigned to a target.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class TargetAssignDistributionSetEvent {
|
||||
|
||||
private final Collection<SoftwareModule> softwareModules;
|
||||
private final String controllerId;
|
||||
private final Long actionId;
|
||||
private final URI targetAdress;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TargetAssignDistributionSetEvent}.
|
||||
*
|
||||
* @param controllerId
|
||||
* the ID of the controller
|
||||
* @param actionId
|
||||
* the action id of the assignment
|
||||
* @param softwareModules
|
||||
* the software modules which have been assigned to the target
|
||||
* @param targetAdress
|
||||
* the targetAdress of the target
|
||||
*/
|
||||
public TargetAssignDistributionSetEvent(final String controllerId, final Long actionId,
|
||||
final Collection<SoftwareModule> softwareModules, final URI targetAdress) {
|
||||
this.controllerId = controllerId;
|
||||
this.actionId = actionId;
|
||||
this.softwareModules = softwareModules;
|
||||
this.targetAdress = targetAdress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the action id of the assignment
|
||||
*/
|
||||
public Long getActionId() {
|
||||
return actionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the controllerId of the Target which has been assigned to the
|
||||
* distribution set
|
||||
*/
|
||||
public String getControllerId() {
|
||||
return controllerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the software modules which have been assigned to the target
|
||||
*/
|
||||
public Collection<SoftwareModule> getSoftwareModules() {
|
||||
return softwareModules;
|
||||
}
|
||||
|
||||
public URI getTargetAdress() {
|
||||
return targetAdress;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.eventbus.event;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
|
||||
/**
|
||||
* Defines the {@link AbstractBaseEntityEvent} of creating a new {@link Target}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class TargetCreatedEvent extends AbstractBaseEntityEvent<Target> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* @param target
|
||||
* the target which has been created
|
||||
*/
|
||||
public TargetCreatedEvent(final Target target) {
|
||||
super(target);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 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.eventbus.event;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class TargetInfoUpdateEvent implements EntityEvent {
|
||||
|
||||
private final long revision;
|
||||
private final TargetInfo targetInfo;
|
||||
private final String tenant;
|
||||
private String originNodeId;
|
||||
private String nodeId;
|
||||
|
||||
/**
|
||||
* @param targetInfo
|
||||
* the target info entity
|
||||
*/
|
||||
public TargetInfoUpdateEvent(final TargetInfo targetInfo) {
|
||||
this.targetInfo = targetInfo;
|
||||
this.tenant = targetInfo.getTarget().getTenant();
|
||||
this.revision = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOriginNodeId(final String originNodeId) {
|
||||
this.originNodeId = originNodeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNodeId(final String nodeId) {
|
||||
this.nodeId = nodeId;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginNodeId() {
|
||||
return this.originNodeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNodeId() {
|
||||
return this.nodeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRevision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E> E getEntity(final Class<E> entityClass) {
|
||||
return entityClass.cast(targetInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetInfo getEntity() {
|
||||
return targetInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTenant() {
|
||||
return tenant;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.report.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An abstract report series.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class AbstractReportSeries implements Serializable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* the name of the series
|
||||
*/
|
||||
public AbstractReportSeries(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the series
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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.report.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A data report series which contains a list of {@link DataReportSeriesItem}.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param <T>
|
||||
* the type of the report series item
|
||||
*/
|
||||
public class DataReportSeries<T extends Object> extends AbstractReportSeries {
|
||||
|
||||
private final List<DataReportSeriesItem<T>> data = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* the name of data series
|
||||
*/
|
||||
public DataReportSeries(final String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a ListSeries with the given series name and array of values.
|
||||
*
|
||||
* @param name
|
||||
* the name of the data series
|
||||
* @param values
|
||||
* data report series item for this data series.
|
||||
*/
|
||||
public DataReportSeries(final String name, final List<DataReportSeriesItem<T>> values) {
|
||||
this(name);
|
||||
setData(values);
|
||||
}
|
||||
|
||||
private void setData(final List<DataReportSeriesItem<T>> values) {
|
||||
this.data.clear();
|
||||
data.addAll(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An array of the numeric values
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public DataReportSeriesItem<T>[] getData() {
|
||||
return data.toArray(new DataReportSeriesItem[data.size()]);
|
||||
}
|
||||
|
||||
public Stream<DataReportSeriesItem<T>> getDataStream() {
|
||||
return data.stream();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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.report.model;
|
||||
|
||||
/**
|
||||
* An data report series item which contains a type and a value.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param <T>
|
||||
* the type of the report series item
|
||||
*/
|
||||
public class DataReportSeriesItem<T extends Object> {
|
||||
|
||||
private final T type;
|
||||
private final Number data;
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* the type of the data report series item
|
||||
* @param data
|
||||
* the data of the report series item
|
||||
*/
|
||||
public DataReportSeriesItem(final T type, final Number data) {
|
||||
this.type = type;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type of the data report item
|
||||
*/
|
||||
public T getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the data of the data report item
|
||||
*/
|
||||
public Number getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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.report.model;
|
||||
|
||||
/**
|
||||
* A double data series which contains an inner and an outer series ideal for
|
||||
* showing donut charts.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param <T>
|
||||
* The type parameter for the report series data
|
||||
*/
|
||||
public class InnerOuterDataReportSeries<T> {
|
||||
|
||||
private final DataReportSeries<T> innerSeries;
|
||||
private final DataReportSeries<T> outerSeries;
|
||||
|
||||
/**
|
||||
* @param innerSeries
|
||||
* the innerseries of an circle donut chart
|
||||
* @param outerSeries
|
||||
* the outer series of an donut chart
|
||||
*/
|
||||
public InnerOuterDataReportSeries(final DataReportSeries<T> innerSeries, final DataReportSeries<T> outerSeries) {
|
||||
this.innerSeries = innerSeries;
|
||||
this.outerSeries = outerSeries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the innerSeries
|
||||
*/
|
||||
public DataReportSeries<T> getInnerSeries() {
|
||||
return innerSeries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the outerSeries
|
||||
*/
|
||||
public DataReportSeries<T> getOuterSeries() {
|
||||
return outerSeries;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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.report.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A simple list report series which just contains a list of values of a report.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ListReportSeries extends AbstractReportSeries {
|
||||
|
||||
private final List<Number> data = new ArrayList<Number>();
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* the name of the list report series
|
||||
*/
|
||||
public ListReportSeries(final String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a ListSeries with the given series name and array of values.
|
||||
*
|
||||
* @param name
|
||||
* the name of the list report series
|
||||
* @param values
|
||||
* the values of the list report series
|
||||
*/
|
||||
public ListReportSeries(final String name, final Number... values) {
|
||||
this(name);
|
||||
setData(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the values in the list series to the ones provided.
|
||||
*
|
||||
* @param values
|
||||
*/
|
||||
private void setData(final Number... values) {
|
||||
this.data.clear();
|
||||
Collections.addAll(this.data, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An array of the numeric values
|
||||
*/
|
||||
public Number[] getData() {
|
||||
return data.toArray(new Number[data.size()]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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.report.model;
|
||||
|
||||
/**
|
||||
* A series time enum definition for {@link DataReportSeriesItem}s.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public enum SeriesTime {
|
||||
|
||||
/**
|
||||
* hour.
|
||||
*/
|
||||
HOUR,
|
||||
/**
|
||||
* day.
|
||||
*/
|
||||
DAY,
|
||||
/**
|
||||
* week.
|
||||
*/
|
||||
WEEK,
|
||||
/**
|
||||
* month.
|
||||
*/
|
||||
MONTH,
|
||||
/**
|
||||
* year.
|
||||
*/
|
||||
YEAR,
|
||||
|
||||
/**
|
||||
* more than one year.
|
||||
*/
|
||||
MORE_THAN_YEAR,
|
||||
|
||||
/**
|
||||
* never.
|
||||
*/
|
||||
NEVER;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link Action} repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface ActionRepository extends BaseEntityRepository<Action, Long>, JpaSpecificationExecutor<Action> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.CrudRepository#findAll()
|
||||
*/
|
||||
@Override
|
||||
@EntityGraph(value = "Action.all", type = EntityGraphType.LOAD)
|
||||
Iterable<Action> findAll();
|
||||
|
||||
/**
|
||||
* Retrieves an Action with all lazy attributes.
|
||||
*
|
||||
* @param actionId
|
||||
* the ID of the action
|
||||
* @return the found {@link Action}
|
||||
*/
|
||||
@EntityGraph(value = "Action.all", type = EntityGraphType.LOAD)
|
||||
Action findById(Long actionId);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are referring the given
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param ds
|
||||
* the {@link DistributionSet} on which will be filtered
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
@EntityGraph(value = "Action.all", type = EntityGraphType.LOAD)
|
||||
Page<Action> findByDistributionSet(final Pageable pageable, final DistributionSet ds);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are referring the given
|
||||
* {@link Target}.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param target
|
||||
* the target to find assigned actions
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
Slice<Action> findByTarget(Pageable pageable, Target target);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are active and referring the given
|
||||
* {@link Target} in a specified order.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param target
|
||||
* the target to find assigned actions
|
||||
* @param active
|
||||
* the action active flag
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
|
||||
List<Action> findByTargetAndActiveOrderByIdAsc(final Target target, boolean active);
|
||||
|
||||
/**
|
||||
* Retrieves latest {@link UpdateAction} for given target and
|
||||
* {@link SoftwareModule}.
|
||||
*
|
||||
* @param targetId
|
||||
* to search for
|
||||
* @param module
|
||||
* to search for
|
||||
* @return action if there is one with assigned target and module is part of
|
||||
* assigned {@link DistributionSet}.
|
||||
*/
|
||||
@Query("Select a from Action a join a.distributionSet ds join ds.modules modul where a.target.controllerId = :target and modul = :module order by a.id desc")
|
||||
List<Action> findActionByTargetAndSoftwareModule(@Param("target") final String targetId,
|
||||
@Param("module") SoftwareModule module);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link UpdateAction}s which are referring the given
|
||||
* {@link DistributionSet} and {@link Target}.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param target
|
||||
* is the assigned target
|
||||
* @param ds
|
||||
* the {@link DistributionSet} on which will be filtered
|
||||
* @return the found {@link UpdateAction}s
|
||||
*/
|
||||
@Query("Select a from Action a where a.target = :target and a.distributionSet = :ds order by a.id")
|
||||
@EntityGraph(value = "Action.all", type = EntityGraphType.LOAD)
|
||||
Page<Action> findByTargetAndDistributionSet(final Pageable pageable, @Param("target") final Target target,
|
||||
@Param("ds") DistributionSet ds);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s of a specific target, without pagination
|
||||
* ordered by action ID.
|
||||
*
|
||||
* @param target
|
||||
* to search for
|
||||
* @return a list of actions according to the searched target
|
||||
*/
|
||||
@Query("Select a from Action a where a.target = :target order by a.id")
|
||||
List<Action> findByTarget(@Param("target") final Target target);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s of a specific target and given active flag
|
||||
* ordered by action ID.
|
||||
*
|
||||
* @param pageable
|
||||
* the pagination parameter
|
||||
* @param target
|
||||
* to search for
|
||||
* @param active
|
||||
* {@code true} for all actions which are currently active,
|
||||
* {@code false} for inactive
|
||||
* @return a paged list of actions ordered by action ID
|
||||
*/
|
||||
@Query("Select a from Action a where a.target = :target and a.active= :active order by a.id")
|
||||
Page<Action> findByActiveAndTarget(Pageable pageable, @Param("target") Target target,
|
||||
@Param("active") boolean active);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s of a specific target and given active flag
|
||||
* ordered by action ID.
|
||||
*
|
||||
* @param target
|
||||
* to search for
|
||||
* @param active
|
||||
* {@code true} for all actions which are currently active,
|
||||
* {@code false} for inactive
|
||||
* @return a list of actions ordered by action ID
|
||||
*/
|
||||
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
|
||||
@Query("Select a from Action a where a.target = :target and a.active= :active order by a.id")
|
||||
List<Action> findByActiveAndTarget(@Param("target") Target target, @Param("active") boolean active);
|
||||
|
||||
/**
|
||||
* Updates all {@link Action} to inactive for all targets with given ID.
|
||||
*
|
||||
* @param keySet
|
||||
* the list of actions to set inactive
|
||||
* @param targetsIds
|
||||
* the IDs of the targets according to the action to set in
|
||||
* active
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("UPDATE Action a SET a.active = false WHERE a IN :keySet AND a.target IN :targetsIds")
|
||||
void setToInactive(@Param("keySet") List<Action> keySet, @Param("targetsIds") List<Long> targetsIds);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are active and referring to the given
|
||||
* target Ids and distribution set required migration step.
|
||||
*
|
||||
* @param targetIds
|
||||
* the IDs of targets for the actions
|
||||
* @param notStatus
|
||||
* the status which the actions should not have
|
||||
* @return the found list of {@link Action}s
|
||||
*/
|
||||
@Query("SELECT a FROM Action a WHERE a.active = true AND a.distributionSet.requiredMigrationStep = false AND a.target IN ?1 AND a.status != ?2")
|
||||
List<Action> findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetRequiredMigrationStep(
|
||||
Collection<Long> targetIds, Action.Status notStatus);
|
||||
|
||||
/**
|
||||
* Counts all {@link Action}s referring to the given target.
|
||||
*
|
||||
* @param target
|
||||
* the target to count the {@link Action}s
|
||||
* @return the count of actions referring to the given target
|
||||
*/
|
||||
Long countByTarget(Target target);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.CrudRepository#save(java.lang.
|
||||
* Iterable)
|
||||
*/
|
||||
@Override
|
||||
@CacheEvict(value = "feedbackReceivedOverTime", allEntries = true)
|
||||
<S extends Action> List<S> save(Iterable<S> entities);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.data.repository.CrudRepository#save(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@CacheEvict(value = "feedbackReceivedOverTime", allEntries = true)
|
||||
<S extends Action> S save(S entity);
|
||||
|
||||
/**
|
||||
* Counts all {@link Action}s referring to the given DistributionSet.
|
||||
*
|
||||
* @param distributionSet
|
||||
* DistributionSet to count the {@link Action}s from
|
||||
* @return the count of actions referring to the given target
|
||||
*/
|
||||
Long countByDistributionSet(DistributionSet distributionSet);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link ActionStatus} repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface ActionStatusRepository
|
||||
extends BaseEntityRepository<ActionStatus, Long>, JpaSpecificationExecutor<ActionStatus> {
|
||||
|
||||
/**
|
||||
* @param target
|
||||
* @param action
|
||||
* @return
|
||||
*/
|
||||
Long countByAction(Action action);
|
||||
|
||||
/**
|
||||
* @param action
|
||||
* @param retrieved
|
||||
* @return
|
||||
*/
|
||||
Long countByActionAndStatus(Action action, Status retrieved);
|
||||
|
||||
/**
|
||||
* @param pageReq
|
||||
* @param action
|
||||
* @return
|
||||
*/
|
||||
Page<ActionStatus> findByAction(Pageable pageReq, Action action);
|
||||
|
||||
/**
|
||||
* @param pageReq
|
||||
* @param action
|
||||
* @return
|
||||
*/
|
||||
Page<ActionStatus> findByActionOrderByIdDesc(Pageable pageReq, Action action);
|
||||
|
||||
/**
|
||||
* Finds all status updates for the defined action and target order by
|
||||
* {@link ActionStatus#getId()} desc including
|
||||
* {@link ActionStatus#getMessages()}.
|
||||
*
|
||||
* @param pageReq
|
||||
* for page configuration
|
||||
* @param target
|
||||
* to look for
|
||||
* @param action
|
||||
* to look for
|
||||
* @return Page with found targets
|
||||
*/
|
||||
@EntityGraph(value = "ActionStatus.withMessages", type = EntityGraphType.LOAD)
|
||||
Page<ActionStatus> getByActionOrderByIdDesc(Pageable pageReq, Action action);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,501 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactStoreException;
|
||||
import org.eclipse.hawkbit.artifact.repository.HashNotMatchException;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactDeleteFailedException;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.GridFSDBFileNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ExternalArtifact;
|
||||
import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider;
|
||||
import org.eclipse.hawkbit.repository.model.LocalArtifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.specifications.SoftwareModuleSpecification;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.hateoas.Identifiable;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* service for {@link Artifact} management operations.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
public class ArtifactManagement {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ArtifactManagement.class);
|
||||
|
||||
@Autowired
|
||||
private LocalArtifactRepository localArtifactRepository;
|
||||
|
||||
@Autowired
|
||||
private ExternalArtifactRepository externalArtifactRepository;
|
||||
|
||||
@Autowired
|
||||
private SoftwareModuleRepository softwareModuleRepository;
|
||||
|
||||
@Autowired
|
||||
private ExternalArtifactProviderRepository externalArtifactProviderRepository;
|
||||
|
||||
@Autowired
|
||||
private ArtifactRepository artifactRepository;
|
||||
|
||||
/**
|
||||
* Persists artifact binary as provided by given InputStream. assign the
|
||||
* artifact in addition to given {@link SoftwareModule}.
|
||||
*
|
||||
* @param stream
|
||||
* to read from for artifact binary
|
||||
* @param moduleId
|
||||
* to assign the new artifact to
|
||||
* @param filename
|
||||
* of the artifact
|
||||
* @param providedSha1Sum
|
||||
* optional sha1 checksum to check the new file against
|
||||
* @param providedMd5Sum
|
||||
* optional md5 checksum to check the new file against
|
||||
* @param overrideExisting
|
||||
* to <code>true</code> if the artifact binary can be overdiden
|
||||
* if it already exists
|
||||
* @param contentType
|
||||
* the contentType of the file
|
||||
* @return uploaded {@link LocalArtifact}
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if given software module does not exist
|
||||
* @throws EntityAlreadyExistsException
|
||||
* if File with that name already exists in the Software Module
|
||||
* @throws ArtifactUploadFailedException
|
||||
* if upload fails with internal server errors
|
||||
* @throws InvalidMD5HashException
|
||||
* if check against provided MD5 checksum failed
|
||||
* @throws InvalidSHA1HashException
|
||||
* if check against provided SHA1 checksum failed
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
public LocalArtifact createLocalArtifact(@NotNull final InputStream stream, @NotNull final Long moduleId,
|
||||
@NotEmpty final String filename, final String providedMd5Sum, final String providedSha1Sum,
|
||||
final boolean overrideExisting, final String contentType) {
|
||||
DbArtifact result = null;
|
||||
|
||||
final SoftwareModule softwareModule = getModuleAndThrowExceptionIfThatFails(moduleId);
|
||||
|
||||
final LocalArtifact existing = checkForExistingArtifact(filename, overrideExisting, softwareModule);
|
||||
|
||||
try {
|
||||
result = artifactRepository.store(stream, filename, contentType,
|
||||
new DbArtifactHash(providedSha1Sum, providedMd5Sum));
|
||||
} catch (final ArtifactStoreException e) {
|
||||
throw new ArtifactUploadFailedException(e);
|
||||
} catch (final HashNotMatchException e) {
|
||||
if (e.getHashFunction().equals(HashNotMatchException.SHA1)) {
|
||||
throw new InvalidSHA1HashException(e.getMessage(), e);
|
||||
} else {
|
||||
throw new InvalidMD5HashException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return storeArtifactMetadata(softwareModule, filename, result, existing);
|
||||
}
|
||||
|
||||
private LocalArtifact checkForExistingArtifact(final String filename, final boolean overrideExisting,
|
||||
final SoftwareModule softwareModule) {
|
||||
if (softwareModule.getLocalArtifactByFilename(filename).isPresent()) {
|
||||
if (overrideExisting) {
|
||||
LOG.debug("overriding existing artifact with new filename {}", filename);
|
||||
return softwareModule.getLocalArtifactByFilename(filename).get();
|
||||
} else {
|
||||
throw new EntityAlreadyExistsException("File with that name already exists in the Software Module");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private SoftwareModule getModuleAndThrowExceptionIfThatFails(final Long moduleId) {
|
||||
final SoftwareModule softwareModule = findSoftwareModuleWithDetails(moduleId);
|
||||
|
||||
if (softwareModule == null) {
|
||||
LOG.debug("no software module with ID {} exists", moduleId);
|
||||
throw new EntityNotFoundException("Software Module: " + moduleId);
|
||||
}
|
||||
return softwareModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves software module including details (
|
||||
* {@link SoftwareModule#getArtifacts()}).
|
||||
*
|
||||
* @param id
|
||||
* parameter
|
||||
* @param isDeleted
|
||||
* parameter
|
||||
* @return the found {@link SoftwareModule}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
protected SoftwareModule findSoftwareModuleWithDetails(@NotNull final Long id) {
|
||||
final SoftwareModule result = findSoftwareModuleById(id);
|
||||
if (result != null) {
|
||||
result.getArtifacts().size();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all local artifact by sha1 and return the first artifact.
|
||||
*
|
||||
* @param sha1
|
||||
* the sha1
|
||||
* @return the first local artifact
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_CONTROLLER)
|
||||
public LocalArtifact findFirstLocalArtifactsBySHA1(final String sha1) {
|
||||
return localArtifactRepository.findFirstByGridFsFileName(sha1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds {@link SoftwareModule} by given id.
|
||||
*
|
||||
* @param id
|
||||
* to search for
|
||||
* @return the found {@link SoftwareModule}s or <code>null</code> if not
|
||||
* found.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_CONTROLLER)
|
||||
protected SoftwareModule findSoftwareModuleById(@NotNull final Long id) {
|
||||
|
||||
final Specification<SoftwareModule> spec = SoftwareModuleSpecification.byId(id);
|
||||
|
||||
return softwareModuleRepository.findOne(spec);
|
||||
}
|
||||
|
||||
private LocalArtifact storeArtifactMetadata(final SoftwareModule softwareModule, final String providedFilename,
|
||||
final DbArtifact result, final LocalArtifact existing) {
|
||||
LocalArtifact artifact = existing;
|
||||
if (existing == null) {
|
||||
artifact = new LocalArtifact(result.getHashes().getSha1(), providedFilename, softwareModule);
|
||||
}
|
||||
artifact.setMd5Hash(result.getHashes().getMd5());
|
||||
artifact.setSha1Hash(result.getHashes().getSha1());
|
||||
artifact.setSize(result.getSize());
|
||||
|
||||
LOG.debug("storing new artifact into repository {}", artifact);
|
||||
final LocalArtifact artifactPersisted = localArtifactRepository.save(artifact);
|
||||
|
||||
return artifactPersisted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists {@link ExternalArtifactProvider} based on given properties.
|
||||
*
|
||||
* @param name
|
||||
* of the provided
|
||||
* @param description
|
||||
* which is optional
|
||||
* @param basePath
|
||||
* of all {@link ExternalArtifact}s of the provider
|
||||
* @param defaultUrlSuffix
|
||||
* that is used if {@link ExternalArtifact#getUrlSuffix()} is
|
||||
* empty.
|
||||
* @return created {@link ExternalArtifactProvider}
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
public ExternalArtifactProvider createExternalArtifactProvider(@NotEmpty final String name,
|
||||
final String description, @NotNull final String basePath, final String defaultUrlSuffix) {
|
||||
return externalArtifactProviderRepository
|
||||
.save(new ExternalArtifactProvider(name, description, basePath, defaultUrlSuffix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link ExternalArtifact} based on given provider.
|
||||
*
|
||||
* @param externalRepository
|
||||
* the artifact is located in
|
||||
* @param urlSuffix
|
||||
* of the artifact
|
||||
* {@link ExternalArtifactProvider#getDefaultSuffix()} is used if
|
||||
* empty.
|
||||
* @param moduleId
|
||||
* to assign the artifact to
|
||||
*
|
||||
* @return created {@link ExternalArtifact}
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if {@link SoftwareModule} with given ID does not exist
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
public ExternalArtifact createExternalArtifact(@NotNull final ExternalArtifactProvider externalRepository,
|
||||
final String urlSuffix, @NotNull final Long moduleId) {
|
||||
|
||||
final SoftwareModule module = getModuleAndThrowExceptionIfThatFails(moduleId);
|
||||
final ExternalArtifact result = externalArtifactRepository
|
||||
.save(new ExternalArtifact(externalRepository, urlSuffix, module));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes {@link Artifact} based on given id.
|
||||
*
|
||||
* @param id
|
||||
* of the {@link Artifact} that has to be deleted.
|
||||
* @throws ArtifactDeleteFailedException
|
||||
* if deletion failed (MongoDB is not available)
|
||||
*
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
||||
public void deleteLocalArtifact(@NotNull final Long id) {
|
||||
final LocalArtifact existing = localArtifactRepository.findOne(id);
|
||||
|
||||
if (null == existing) {
|
||||
return;
|
||||
}
|
||||
|
||||
deleteGridFsArtifact(existing);
|
||||
|
||||
existing.getSoftwareModule().removeArtifact(existing);
|
||||
softwareModuleRepository.save(existing.getSoftwareModule());
|
||||
localArtifactRepository.delete(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a grid fs file.
|
||||
*
|
||||
* @param existing
|
||||
* the related local artifact
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
||||
public void deleteGridFsArtifact(@NotNull final LocalArtifact existing) {
|
||||
if (existing == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean artifactIsOnlyUsedByOneSoftwareModule = true;
|
||||
for (LocalArtifact lArtifact : localArtifactRepository.findByGridFsFileName(existing.getGridFsFileName())) {
|
||||
if (!lArtifact.getSoftwareModule().isDeleted()
|
||||
&& lArtifact.getSoftwareModule().getId() != existing.getSoftwareModule().getId()) {
|
||||
artifactIsOnlyUsedByOneSoftwareModule = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (artifactIsOnlyUsedByOneSoftwareModule) {
|
||||
try {
|
||||
LOG.debug("deleting artifact from repository {}", existing.getGridFsFileName());
|
||||
artifactRepository.deleteBySha1(existing.getGridFsFileName());
|
||||
} catch (final ArtifactStoreException e) {
|
||||
throw new ArtifactDeleteFailedException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes {@link Artifact} based on given id.
|
||||
*
|
||||
* @param id
|
||||
* of the {@link Artifact} that has to be deleted.
|
||||
* @throws ArtifactDeleteFailedException
|
||||
* if deletion failed (MongoDB is not available)
|
||||
*
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
||||
public void deleteExternalArtifact(@NotNull final Long id) {
|
||||
final ExternalArtifact existing = externalArtifactRepository.findOne(id);
|
||||
|
||||
if (null == existing) {
|
||||
return;
|
||||
}
|
||||
|
||||
existing.getSoftwareModule().removeArtifact(existing);
|
||||
softwareModuleRepository.save(existing.getSoftwareModule());
|
||||
externalArtifactRepository.delete(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for {@link Artifact} with given file name.
|
||||
*
|
||||
* @param filename
|
||||
* to search for
|
||||
* @return found List of {@link LocalArtifact}s.
|
||||
*/
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_CONTROLLER)
|
||||
public List<LocalArtifact> findLocalArtifactByFilename(@NotNull final String filename) {
|
||||
return localArtifactRepository.findByFilename(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for {@link Artifact} with given {@link Identifiable}.
|
||||
*
|
||||
* @param id
|
||||
* to search for
|
||||
* @return found {@link Artifact} or <code>null</code> is it could not be
|
||||
* found.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Artifact findArtifact(@NotNull final Long id) {
|
||||
return localArtifactRepository.findOne(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads {@link org.eclipse.hawkbit.artifact.server.json.model.Artifact}
|
||||
* from store for given {@link LocalArtifact}.
|
||||
*
|
||||
* @param artifact
|
||||
* to search for
|
||||
* @return loaded
|
||||
* {@link org.eclipse.hawkbit.artifact.server.json.model.Artifact}
|
||||
*
|
||||
* @throws GridFSDBFileNotFoundException
|
||||
* if file could not be found in store
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DOWNLOAD_ARTIFACT + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_CONTROLLER)
|
||||
public DbArtifact loadLocalArtifactBinary(@NotNull final LocalArtifact artifact) {
|
||||
final DbArtifact result = artifactRepository.getArtifactBySha1(artifact.getGridFsFileName());
|
||||
if (result == null) {
|
||||
throw new GridFSDBFileNotFoundException(artifact.getGridFsFileName());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists artifact binary as provided by given InputStream. assign the
|
||||
* artifact in addition to given {@link SoftwareModule}.
|
||||
*
|
||||
* @param inputStream
|
||||
* to read from for artifact binary
|
||||
* @param moduleId
|
||||
* to assign the new artifact to
|
||||
* @param filename
|
||||
* of the artifact
|
||||
* @param overrideExisting
|
||||
* to <code>true</code> if the artifact binary can be overdiden
|
||||
* if it already exists
|
||||
* @param contentType
|
||||
* the contentType of the file
|
||||
*
|
||||
* @return uploaded {@link LocalArtifact}
|
||||
*
|
||||
* @throw ArtifactUploadFailedException if upload failes
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
public LocalArtifact createLocalArtifact(final InputStream inputStream, final Long moduleId, final String filename,
|
||||
final boolean overrideExisting, final String contentType) {
|
||||
return createLocalArtifact(inputStream, moduleId, filename, null, null, overrideExisting, contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists artifact binary as provided by given InputStream. assign the
|
||||
* artifact in addition to given {@link SoftwareModule}.
|
||||
*
|
||||
* @param inputStream
|
||||
* to read from for artifact binary
|
||||
* @param moduleId
|
||||
* to assign the new artifact to
|
||||
* @param filename
|
||||
* of the artifact
|
||||
* @param overrideExisting
|
||||
* to <code>true</code> if the artifact binary can be overdiden
|
||||
* if it already exists
|
||||
*
|
||||
* @return uploaded {@link LocalArtifact}
|
||||
*
|
||||
* @throw ArtifactUploadFailedException if upload failes
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
public LocalArtifact createLocalArtifact(final InputStream inputStream, final Long moduleId, final String filename,
|
||||
final boolean overrideExisting) {
|
||||
return createLocalArtifact(inputStream, moduleId, filename, null, null, overrideExisting, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local artifact for a base software module.
|
||||
*
|
||||
* @param pageReq
|
||||
* Pageable
|
||||
* @param swId
|
||||
* software module id
|
||||
* @return Page<LocalArtifact>
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Page<LocalArtifact> findLocalArtifactBySoftwareModule(@NotNull final Pageable pageReq,
|
||||
@NotNull final Long swId) {
|
||||
return localArtifactRepository.findBySoftwareModuleId(pageReq, swId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find by artifact by software module id and filename.
|
||||
*
|
||||
* @param filename
|
||||
* file name
|
||||
* @param softwareModuleId
|
||||
* software module id.
|
||||
* @return LocalArtifact if artifact present
|
||||
*/
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_CONTROLLER)
|
||||
public List<LocalArtifact> findByFilenameAndSoftwareModule(@NotNull final String filename,
|
||||
@NotNull final Long softwareModuleId) {
|
||||
return localArtifactRepository.findByFilenameAndSoftwareModuleId(filename, softwareModuleId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Generic assigment result bean.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class AssignmentResult {
|
||||
|
||||
private final int total;
|
||||
private final int assigned;
|
||||
private final int alreadyAssigned;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param assigned
|
||||
* is the number of newly assigned elements.
|
||||
* @param alreadyAssigned
|
||||
* is the number of already assigned elements.
|
||||
*/
|
||||
public AssignmentResult(final int assigned, final int alreadyAssigned) {
|
||||
super();
|
||||
this.assigned = assigned;
|
||||
this.alreadyAssigned = alreadyAssigned;
|
||||
total = assigned + alreadyAssigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the assignedTargets
|
||||
*/
|
||||
public int getAssigned() {
|
||||
return assigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the total
|
||||
*/
|
||||
public int getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the alreadyAssigned
|
||||
*/
|
||||
public int getAlreadyAssigned() {
|
||||
return alreadyAssigned;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Command repository operations for all {@link BaseEntity}s.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param <T>
|
||||
* type if the entity type
|
||||
* @param <I>
|
||||
* of the entity type
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
@Transactional(readOnly = true)
|
||||
public interface BaseEntityRepository<T extends BaseEntity, I extends Serializable>
|
||||
extends PagingAndSortingRepository<T, I> {
|
||||
|
||||
/**
|
||||
* Deletes all {@link BaseEntity} of a given tenant.
|
||||
*
|
||||
* @param tenant
|
||||
* to delete data from
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
void deleteByTenantIgnoreCase(String tenant);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,588 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException;
|
||||
import org.eclipse.hawkbit.repository.exception.ToManyStatusEntriesException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus_;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Target_;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* Service layer for all operations of the controller API (with access
|
||||
* permissions only for the controller).
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
public class ControllerManagement implements EnvironmentAware {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ControllerManagement.class);
|
||||
private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos");
|
||||
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
private ActionRepository actionRepository;
|
||||
|
||||
@Autowired
|
||||
private TargetRepository targetRepository;
|
||||
|
||||
@Autowired
|
||||
private TargetManagement targetManagement;
|
||||
|
||||
@Autowired
|
||||
private DeploymentManagement deploymentManagement;
|
||||
|
||||
@Autowired
|
||||
private TargetInfoRepository targetInfoRepository;
|
||||
|
||||
@Autowired
|
||||
private SoftwareModuleRepository softwareModuleRepository;
|
||||
|
||||
@Autowired
|
||||
private ActionStatusRepository actionStatusRepository;
|
||||
|
||||
private Integer maxCount = 1000;
|
||||
|
||||
private Integer maxAttributes = 100;
|
||||
|
||||
/**
|
||||
* Refreshes the time of the last time the controller has been connected to
|
||||
* the server.
|
||||
*
|
||||
* @param targetid
|
||||
* of the target to to update
|
||||
* @param address
|
||||
* the client address of the target, might be {@code null}
|
||||
* @return the updated target
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if target with given ID could not be found
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public Target updateLastTargetQuery(@NotEmpty final String targetid, final URI address) {
|
||||
final Target target = targetRepository.findByControllerId(targetid);
|
||||
if (target == null) {
|
||||
throw new EntityNotFoundException(targetid);
|
||||
}
|
||||
|
||||
return updateLastTargetQuery(target.getTargetInfo(), address).getTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves last {@link UpdateAction} for a download of an artifact of
|
||||
* given module and target.
|
||||
*
|
||||
* @param targetId
|
||||
* to look for
|
||||
* @param module
|
||||
* that should be assigned to the target
|
||||
* @return last {@link UpdateAction} for given combination
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if action for given combination could not be found
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public Action getActionForDownloadByTargetAndSoftwareModule(@NotNull final String targetId,
|
||||
@NotNull final SoftwareModule module) {
|
||||
final List<Action> action = actionRepository.findActionByTargetAndSoftwareModule(targetId, module);
|
||||
|
||||
if (action.isEmpty() || action.get(0).isCancelingOrCanceled()) {
|
||||
throw new EntityNotFoundException("No assigment found for module " + module.getId() + " to target "
|
||||
+ targetId);
|
||||
}
|
||||
|
||||
return action.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the time of the last time the controller has been connected to
|
||||
* the server.
|
||||
*
|
||||
* @param target
|
||||
* to update
|
||||
* @param address
|
||||
* the client address of the target, might be {@code null}
|
||||
* @return the updated target
|
||||
*
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public TargetInfo updateLastTargetQuery(@NotNull final TargetInfo target, final URI address) {
|
||||
return updateTargetStatus(target, null, System.currentTimeMillis(), address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are active and assigned to a
|
||||
* {@link Target}.
|
||||
*
|
||||
* @param target
|
||||
* the target to retrieve the actions from
|
||||
* @return a list of actions assigned to given target which are active
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public List<Action> findActionByTargetAndActive(final Target target) {
|
||||
return actionRepository.findByTargetAndActiveOrderByIdAsc(target, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all {@link SoftwareModule}s which are assigned to the given
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @param distributionSet
|
||||
* the distribution set which should be assigned to the returned
|
||||
* {@link SoftwareModule}s
|
||||
* @return a list of {@link SoftwareModule}s assigned to given
|
||||
* {@code distributionSet}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public List<SoftwareModule> findSoftwareModulesByDistributionSet(final DistributionSet distributionSet) {
|
||||
return softwareModuleRepository.findByAssignedTo(distributionSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Action} entity for given actionId with all lazy
|
||||
* attributes.
|
||||
*
|
||||
* @param actionId
|
||||
* to be id of the action
|
||||
* @return the corresponding {@link Action}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public Action findActionWithDetails(@NotNull final Long actionId) {
|
||||
return actionRepository.findById(actionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* register new target in the repository (plug-and-play).
|
||||
*
|
||||
* @param targetid
|
||||
* reference
|
||||
* @param address
|
||||
* the client IP address of the target, might be {@code null}
|
||||
* @return target reference
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public Target findOrRegisterTargetIfItDoesNotexist(@NotNull final String targetid, final URI address) {
|
||||
final Specification<Target> spec = new Specification<Target>() {
|
||||
@Override
|
||||
public Predicate toPredicate(final Root<Target> targetRoot, final CriteriaQuery<?> query,
|
||||
final CriteriaBuilder cb) {
|
||||
return cb.equal(targetRoot.get(Target_.controllerId), targetid);
|
||||
}
|
||||
};
|
||||
|
||||
Target target = targetRepository.findOne(spec);
|
||||
|
||||
if (target == null) {
|
||||
target = new Target(targetid);
|
||||
target.setDescription("Plug and Play target: " + targetid);
|
||||
target.setName(targetid);
|
||||
return targetManagement.createTarget(target, TargetUpdateStatus.REGISTERED, System.currentTimeMillis(),
|
||||
address);
|
||||
} else {
|
||||
return updateLastTargetQuery(target.getTargetInfo(), address).getTarget();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update selective the target status of a given {@code target}.
|
||||
*
|
||||
* @param targetInfo
|
||||
* the target to update the target status
|
||||
* @param status
|
||||
* the status to be set of the target. Might be {@code null} if
|
||||
* the target status should not be updated
|
||||
* @param lastTargetQuery
|
||||
* the last target query to be set of the target. Might be
|
||||
* {@code null} if the target lastTargetQuery should not be
|
||||
* updated
|
||||
* @param address
|
||||
* the client address of the target, might be {@code null}
|
||||
* @return the updated TargetInfo
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public TargetInfo updateTargetStatus(@NotNull final TargetInfo targetInfo, final TargetUpdateStatus status,
|
||||
final Long lastTargetQuery, final URI address) {
|
||||
final TargetInfo mtargetInfo = entityManager.merge(targetInfo);
|
||||
if (status != null) {
|
||||
mtargetInfo.setUpdateStatus(status);
|
||||
}
|
||||
if (lastTargetQuery != null) {
|
||||
mtargetInfo.setLastTargetQuery(lastTargetQuery);
|
||||
}
|
||||
if (address != null) {
|
||||
mtargetInfo.setAddress(address.toString());
|
||||
}
|
||||
return targetInfoRepository.save(mtargetInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an {@link ActionStatus} for a {@link CancelAction}.
|
||||
*
|
||||
* @param actionStatusMessages
|
||||
* to be updated
|
||||
* @param target2
|
||||
*
|
||||
* @throws EntityAlreadyExistsException
|
||||
* if a given entity already exists
|
||||
* @throws ToManyStatusEntriesException
|
||||
* if more than the allowed number of status entries are
|
||||
* inserted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public void addCancelActionStatus(@NotNull final ActionStatus actionStatus, final Action action) {
|
||||
|
||||
checkForToManyStatusEntries(action);
|
||||
action.setStatus(actionStatus.getStatus());
|
||||
|
||||
switch (actionStatus.getStatus()) {
|
||||
case WARNING:
|
||||
case ERROR:
|
||||
case RUNNING:
|
||||
break;
|
||||
case CANCELED:
|
||||
case FINISHED:
|
||||
// in case of successful cancelation we also report the success at
|
||||
// the canceled action
|
||||
// itself.
|
||||
actionStatus.addMessage("Cancelation completion is finished sucessfully.");
|
||||
// set action inactive
|
||||
action.setActive(false);
|
||||
successCancellation(action);
|
||||
break;
|
||||
case RETRIEVED:
|
||||
actionStatus.addMessage("Cancelation request retrieved");
|
||||
break;
|
||||
default:
|
||||
}
|
||||
actionRepository.save(action);
|
||||
actionStatusRepository.save(actionStatus);
|
||||
}
|
||||
|
||||
private void successCancellation(final Action action) {
|
||||
final Target target = action.getTarget();
|
||||
final List<Action> nextActiveActions = actionRepository.findByTargetAndActiveOrderByIdAsc(target, true)
|
||||
.stream().filter(a -> !a.getId().equals(action.getId())).collect(Collectors.toList());
|
||||
|
||||
if (nextActiveActions.isEmpty()) {
|
||||
target.setAssignedDistributionSet(target.getTargetInfo().getInstalledDistributionSet());
|
||||
deploymentManagement.updateTargetInfo(target, TargetUpdateStatus.IN_SYNC, false);
|
||||
} else {
|
||||
target.setAssignedDistributionSet(nextActiveActions.get(0).getDistributionSet());
|
||||
}
|
||||
targetManagement.updateTarget(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an {@link ActionStatus} for a {@link UpdateAction}.
|
||||
*
|
||||
* @param actionStatus
|
||||
* to be updated
|
||||
* @param action
|
||||
* the update is for
|
||||
* @return the persisted {@link ActionStatus}
|
||||
*
|
||||
* @throws EntityAlreadyExistsException
|
||||
* if a given entity already exists
|
||||
* @throws ToManyStatusEntriesException
|
||||
* if more than the allowed number of status entries are
|
||||
* inserted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public Action addUpdateActionStatus(@NotNull final ActionStatus actionStatus, final Action action) {
|
||||
|
||||
if (!action.isActive()) {
|
||||
LOG.debug("Update of actionStatus {} for action {} not possible since action not active anymore.",
|
||||
actionStatus.getId(), action.getId());
|
||||
return action;
|
||||
}
|
||||
return handleAddUpdateActionStatus(actionStatus, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link TargetUpdateStatus} based on given {@link ActionStatus}.
|
||||
*
|
||||
* @param actionStatus
|
||||
* @param action
|
||||
* @return
|
||||
*/
|
||||
public Action handleAddUpdateActionStatus(final ActionStatus actionStatus, final Action action) {
|
||||
LOG.debug("addUpdateActionStatus for action {}", action.getId());
|
||||
|
||||
final Action mergedAction = entityManager.merge(action);
|
||||
Target mergedTarget = mergedAction.getTarget();
|
||||
// check for a potential DOS attack
|
||||
checkForToManyStatusEntries(action);
|
||||
|
||||
switch (actionStatus.getStatus()) {
|
||||
case ERROR:
|
||||
mergedTarget = deploymentManagement.updateTargetInfo(mergedTarget, TargetUpdateStatus.ERROR, false);
|
||||
// set action inactive
|
||||
mergedAction.setActive(false);
|
||||
mergedAction.setStatus(Status.ERROR);
|
||||
mergedTarget.setAssignedDistributionSet(null);
|
||||
targetManagement.updateTarget(mergedTarget);
|
||||
break;
|
||||
case FINISHED:
|
||||
// set action inactive
|
||||
mergedAction.setActive(false);
|
||||
mergedAction.setStatus(Status.FINISHED);
|
||||
handleFinishedAndStoreInTargetStatus(mergedTarget, mergedAction);
|
||||
break;
|
||||
case CANCELED:
|
||||
case WARNING:
|
||||
case RUNNING:
|
||||
deploymentManagement.updateTargetInfo(mergedTarget, TargetUpdateStatus.PENDING, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
actionStatusRepository.save(actionStatus);
|
||||
|
||||
LOG.debug("addUpdateActionStatus {} for target {} is finished.", action.getId(), mergedTarget.getId());
|
||||
|
||||
return actionRepository.save(mergedAction);
|
||||
}
|
||||
|
||||
private void checkForToManyStatusEntries(final Action action) {
|
||||
if (maxCount > 0) {
|
||||
|
||||
final Long statusCount = actionStatusRepository.countByAction(action);
|
||||
|
||||
if (statusCount >= maxCount) {
|
||||
LOG_DOS.error(
|
||||
"Potential denial of service (DOS) attack identfied. More status entries in the system than permitted ({})!",
|
||||
maxCount);
|
||||
throw new ToManyStatusEntriesException(String.valueOf(maxCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFinishedAndStoreInTargetStatus(final Target target, final Action action) {
|
||||
final TargetInfo targetInfo = target.getTargetInfo();
|
||||
final DistributionSet ds = entityManager.merge(action.getDistributionSet());
|
||||
targetInfo.setInstalledDistributionSet(ds);
|
||||
if (target.getAssignedDistributionSet() != null && targetInfo.getInstalledDistributionSet() != null
|
||||
&& target.getAssignedDistributionSet().getId().equals(targetInfo.getInstalledDistributionSet().getId())) {
|
||||
targetInfo.setUpdateStatus(TargetUpdateStatus.IN_SYNC);
|
||||
targetInfo.setInstallationDate(System.currentTimeMillis());
|
||||
} else {
|
||||
targetInfo.setUpdateStatus(TargetUpdateStatus.PENDING);
|
||||
targetInfo.setInstallationDate(System.currentTimeMillis());
|
||||
}
|
||||
targetInfoRepository.save(targetInfo);
|
||||
entityManager.detach(ds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates attributes of the controller.
|
||||
*
|
||||
* @param targetid
|
||||
* to update
|
||||
* @param data
|
||||
* to insert
|
||||
*
|
||||
* @return updated {@link Target}
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if target that has to be updated could not be found
|
||||
* @throws ToManyAttributeEntriesException
|
||||
* if maximum
|
||||
*/
|
||||
@Modifying
|
||||
@NotNull
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public Target updateControllerAttributes(@NotEmpty final String targetid, @NotNull final Map<String, String> data) {
|
||||
final Target target = targetRepository.findByControllerId(targetid);
|
||||
|
||||
if (target == null) {
|
||||
throw new EntityNotFoundException(targetid);
|
||||
}
|
||||
|
||||
target.getTargetInfo().getControllerAttributes().putAll(data);
|
||||
|
||||
if (target.getTargetInfo().getControllerAttributes().size() > maxAttributes) {
|
||||
LOG_DOS.info(
|
||||
"Target tries to insert more than the allowed number of entries ({}). DOS attack anticipated!",
|
||||
maxAttributes);
|
||||
throw new ToManyAttributeEntriesException(String.valueOf(maxAttributes));
|
||||
}
|
||||
|
||||
target.getTargetInfo().setLastTargetQuery(System.currentTimeMillis());
|
||||
target.getTargetInfo().setRequestControllerAttributes(false);
|
||||
return targetRepository.save(target);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.context.EnvironmentAware#setEnvironment(org.
|
||||
* springframework.core.env. Environment)
|
||||
*/
|
||||
@Override
|
||||
public void setEnvironment(final Environment environment) {
|
||||
final RelaxedPropertyResolver env = new RelaxedPropertyResolver(environment, "hawkbit.server.");
|
||||
maxCount = env.getProperty("security.dos.maxStatusEntriesPerAction", Integer.class, 1000);
|
||||
maxAttributes = env.getProperty("security.dos.maxAttributeEntriesPerTarget", Integer.class, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers retrieved status for given {@link Target} and {@link Action} if
|
||||
* it does not exist yet.
|
||||
*
|
||||
* @param action
|
||||
* to the handle status for
|
||||
* @param target
|
||||
* to the handle status for
|
||||
* @param message
|
||||
* for the status
|
||||
* @return the update action in case the status has been changed to
|
||||
* {@link Status#RETRIEVED}
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public Action registerRetrieved(final Action action, final String message) {
|
||||
return handleRegisterRetrieved(action, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers retrieved status for given {@link Target} and {@link Action} if
|
||||
* it does not exist yet.
|
||||
*
|
||||
* @param action
|
||||
* to the handle status for
|
||||
* @param message
|
||||
* for the status
|
||||
* @return the updated action in case the status has been changed to
|
||||
* {@link Status#RETRIEVED}
|
||||
*/
|
||||
public Action handleRegisterRetrieved(final Action action, final String message) {
|
||||
// do a manual query with CriteriaBuilder to avoid unnecessary field
|
||||
// queries and an extra
|
||||
// count query made by spring-data when using pageable requests, we
|
||||
// don't need an extra count
|
||||
// query, we just want to check if the last action status is a retrieved
|
||||
// or not.
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Object[]> queryActionStatus = cb.createQuery(Object[].class);
|
||||
final Root<ActionStatus> actionStatusRoot = queryActionStatus.from(ActionStatus.class);
|
||||
final CriteriaQuery<Object[]> query = queryActionStatus
|
||||
.multiselect(actionStatusRoot.get(ActionStatus_.id), actionStatusRoot.get(ActionStatus_.status))
|
||||
.where(cb.equal(actionStatusRoot.get(ActionStatus_.action), action))
|
||||
.orderBy(cb.desc(actionStatusRoot.get(ActionStatus_.id)));
|
||||
final List<Object[]> resultList = entityManager.createQuery(query).setFirstResult(0).setMaxResults(1)
|
||||
.getResultList();
|
||||
|
||||
// if the latest status is not in retrieve state then we add a retrieved
|
||||
// state again, we want
|
||||
// to document a deployment retrieved status and a cancel retrieved
|
||||
// status, but multiple
|
||||
// retrieves after the other we don't want to store to protect to
|
||||
// overflood action status in
|
||||
// case controller retrieves a action multiple times.
|
||||
if (resultList.isEmpty() || resultList.get(0)[1] != Status.RETRIEVED) {
|
||||
// document that the status has been retrieved
|
||||
actionStatusRepository
|
||||
.save(new ActionStatus(action, Status.RETRIEVED, System.currentTimeMillis(), message));
|
||||
|
||||
// don't change the action status itself in case the action is in
|
||||
// canceling state otherwise
|
||||
// we modify the action status and the controller won't get the
|
||||
// cancel job anymore.
|
||||
if (!action.isCancelingOrCanceled()) {
|
||||
final Action actionMerge = entityManager.merge(action);
|
||||
actionMerge.setStatus(Status.RETRIEVED);
|
||||
return actionRepository.save(actionMerge);
|
||||
}
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param statusMessage
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
@Modifying
|
||||
@Transactional
|
||||
public void addActionStatusMessage(final ActionStatus statusMessage) {
|
||||
actionStatusRepository.save(statusMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* An direct access to the security token of an
|
||||
* {@link Target#getSecurityToken()} without authorization. This is
|
||||
* necessary to be able to access the security-token without any
|
||||
* security-context information because the security-token is used for
|
||||
* authentication.
|
||||
*
|
||||
* @param controllerId
|
||||
* the ID of the controller to retrieve the security token for
|
||||
* @return the security context of the target, in case no target exists for
|
||||
* the given controllerId {@code null} is returned
|
||||
*/
|
||||
@Transactional
|
||||
public String getSecurityTokenByControllerId(final String controllerId) {
|
||||
final Target target = targetRepository.findByControllerId(controllerId);
|
||||
return target != null ? target.getSecurityToken() : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,706 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.Constants;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.event.DeploymentManagementEvents;
|
||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.ActionWithStatusCount;
|
||||
import org.eclipse.hawkbit.repository.model.Action_;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.specifications.TargetSpecifications;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* Business service facade for managing all deployment related data and actions.
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
public class DeploymentManagement {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DeploymentManagement.class);
|
||||
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
private ActionRepository actionRepository;
|
||||
|
||||
@Autowired
|
||||
private DistributionSetRepository distributoinSetRepository;
|
||||
|
||||
@Autowired
|
||||
private SoftwareModuleRepository softwareModuleRepository;
|
||||
|
||||
@Autowired
|
||||
private TargetRepository targetRepository;
|
||||
|
||||
@Autowired
|
||||
private ActionStatusRepository actionStatusRepository;
|
||||
|
||||
@Autowired
|
||||
private TargetManagement targetManagement;
|
||||
|
||||
@Autowired
|
||||
private TargetInfoRepository targetInfoRepository;
|
||||
|
||||
@Autowired
|
||||
private AuditorAware<String> auditorProvider;
|
||||
|
||||
@Autowired
|
||||
private DeploymentManagementEvents deploymentManagementEvents;
|
||||
|
||||
/**
|
||||
* method assigns the {@link DistributionSet} to all {@link Target}s.
|
||||
*
|
||||
* @param pset
|
||||
* {@link DistributionSet} which is assigned to the
|
||||
* {@link Target}s
|
||||
* @param targets
|
||||
* the {@link Target}s which should obtain the
|
||||
* {@link DistributionSet}
|
||||
*
|
||||
* @return the changed targets
|
||||
*
|
||||
* @throw IncompleteDistributionSetException if mandatory
|
||||
* {@link SoftwareModuleType} are not assigned as define by the
|
||||
* {@link DistributionSetType}. *
|
||||
*/
|
||||
@Transactional
|
||||
@Modifying
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
|
||||
@CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true)
|
||||
public DistributionSetAssignmentResult assignDistributionSet(@NotNull final DistributionSet pset,
|
||||
@NotEmpty final List<Target> targets) {
|
||||
|
||||
return assignDistributionSetByTargetId(pset,
|
||||
targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()),
|
||||
ActionType.FORCED, Action.NO_FORCE_TIME);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* method assigns the {@link DistributionSet} to all {@link Target}s by
|
||||
* their IDs.
|
||||
*
|
||||
* @param dsID
|
||||
* {@link DistributionSet} which is assigned to the
|
||||
* {@link Target}s
|
||||
* @param targetIDs
|
||||
* IDs of the {@link Target}s which should obtain the
|
||||
* {@link DistributionSet}
|
||||
*
|
||||
* @return the changed targets
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if {@link DistributionSet} does not exist.
|
||||
*
|
||||
* @throw IncompleteDistributionSetException if mandatory
|
||||
* {@link SoftwareModuleType} are not assigned as define by the
|
||||
* {@link DistributionSetType}.
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
|
||||
@CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true)
|
||||
public DistributionSetAssignmentResult assignDistributionSet(@NotNull final Long dsID,
|
||||
@NotEmpty final String... targetIDs) {
|
||||
return assignDistributionSet(dsID, ActionType.FORCED, Action.NO_FORCE_TIME, targetIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* method assigns the {@link DistributionSet} to all {@link Target}s by
|
||||
* their IDs with a specific {@link ActionType} and {@code forcetime}.
|
||||
*
|
||||
* @param dsID
|
||||
* the ID of the distribution set to assign
|
||||
* @param actionType
|
||||
* the type of the action to apply on the assignment
|
||||
* @param forcedTimestamp
|
||||
* the time when the action should be forced, only necessary for
|
||||
* {@link ActionType#TIMEFORCED}
|
||||
* @param targetIDs
|
||||
* the IDs of the target to assign the distribution set
|
||||
* @return the assignment result
|
||||
*
|
||||
* @throw IncompleteDistributionSetException if mandatory
|
||||
* {@link SoftwareModuleType} are not assigned as define by the
|
||||
* {@link DistributionSetType}.
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
|
||||
@CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true)
|
||||
public DistributionSetAssignmentResult assignDistributionSet(@NotNull final Long dsID, final ActionType actionType,
|
||||
final long forcedTimestamp, @NotEmpty final String... targetIDs) {
|
||||
return assignDistributionSet(dsID, Arrays.stream(targetIDs)
|
||||
.map(t -> new TargetWithActionType(t, actionType, forcedTimestamp)).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* method assigns the {@link DistributionSet} to all {@link Target}s by
|
||||
* their IDs with a specific {@link ActionType} and {@code forcetime}.
|
||||
*
|
||||
* @param dsID
|
||||
* the ID of the distribution set to assign
|
||||
* @param targets
|
||||
* a list of all targets and their action type
|
||||
* @return the assignment result
|
||||
*
|
||||
* @throw IncompleteDistributionSetException if mandatory
|
||||
* {@link SoftwareModuleType} are not assigned as define by the
|
||||
* {@link DistributionSetType}.
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
|
||||
@CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true)
|
||||
public DistributionSetAssignmentResult assignDistributionSet(@NotNull final Long dsID,
|
||||
final List<TargetWithActionType> targets) {
|
||||
final DistributionSet set = distributoinSetRepository.findOne(dsID);
|
||||
if (set == null) {
|
||||
throw new EntityNotFoundException(
|
||||
String.format("no %s with id %d found", DistributionSet.class.getSimpleName(), dsID));
|
||||
}
|
||||
|
||||
return assignDistributionSetToTargets(set, targets);
|
||||
}
|
||||
|
||||
/**
|
||||
* method assigns the {@link DistributionSet} to all {@link Target}s by
|
||||
* their IDs with a specific {@link ActionType} and {@code forcetime}.
|
||||
*
|
||||
* @param dsID
|
||||
* the ID of the distribution set to assign
|
||||
* @param targetsWithActionType
|
||||
* a list of all targets and their action type
|
||||
* @return the assignment result
|
||||
*
|
||||
* @throw IncompleteDistributionSetException if mandatory
|
||||
* {@link SoftwareModuleType} are not assigned as define by the
|
||||
* {@link DistributionSetType}.
|
||||
*/
|
||||
private DistributionSetAssignmentResult assignDistributionSetToTargets(@NotNull final DistributionSet set,
|
||||
final List<TargetWithActionType> targetsWithActionType) {
|
||||
|
||||
if (!set.isComplete()) {
|
||||
throw new IncompleteDistributionSetException(
|
||||
"Distribution set of type " + set.getType().getKey() + " is incomplete: " + set.getId());
|
||||
}
|
||||
|
||||
final List<String> controllerIDs = targetsWithActionType.stream().map(TargetWithActionType::getTargetId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
LOG.debug("assignDistribution({}) to {} targets", set, controllerIDs.size());
|
||||
|
||||
final Map<String, TargetWithActionType> targetsWithActionMap = targetsWithActionType.stream()
|
||||
.collect(Collectors.toMap(TargetWithActionType::getTargetId, Function.identity()));
|
||||
|
||||
// split tIDs length into max entries in-statement because many database
|
||||
// have constraint of
|
||||
// max entries in in-statements e.g. Oracle with maximum 1000 elements,
|
||||
// so we need to split
|
||||
// the entries here and execute multiple statements
|
||||
// we take the target only into account if the requested operation is no
|
||||
// duplicate of a
|
||||
// previous one
|
||||
final List<Target> targets = Lists.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT).stream()
|
||||
.map(ids -> targetRepository
|
||||
.findAll(TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, set.getId())))
|
||||
.flatMap(t -> t.stream()).collect(Collectors.toList());
|
||||
|
||||
if (targets.isEmpty()) {
|
||||
// detaching as it is not necessary to persist the set itself
|
||||
entityManager.detach(set);
|
||||
// return with nothing as all targets had the DS already assigned
|
||||
return new DistributionSetAssignmentResult(Collections.emptyList(), 0, targetsWithActionType.size(),
|
||||
Collections.emptyList(), targetManagement);
|
||||
}
|
||||
|
||||
final List<List<Long>> targetIds = Lists.partition(
|
||||
targets.stream().map(Target::getId).collect(Collectors.toList()), Constants.MAX_ENTRIES_IN_STATEMENT);
|
||||
|
||||
// override all active actions and set them into canceling state, we
|
||||
// need to remember which
|
||||
// one we have been switched to canceling state because for targets
|
||||
// which we have changed to
|
||||
// canceling we don't want to publish the new action update event.
|
||||
final Set<Long> targetIdsCancellList = new HashSet<Long>();
|
||||
targetIds.forEach(ids -> targetIdsCancellList.addAll(overrideObsoleteUpdateActions(ids)));
|
||||
|
||||
// check for old assigments that needs cancelation
|
||||
// final List<Long> canncelledTargetIds =
|
||||
|
||||
// set assigned distribution set and TargetUpdateStatus
|
||||
final String currentUser;
|
||||
if (auditorProvider != null) {
|
||||
currentUser = auditorProvider.getCurrentAuditor();
|
||||
} else {
|
||||
currentUser = null;
|
||||
}
|
||||
|
||||
targetIds.forEach(tIds -> targetRepository.setAssignedDistributionSet(set, System.currentTimeMillis(),
|
||||
currentUser, tIds));
|
||||
targetIds.forEach(tIds -> targetInfoRepository.setTargetUpdateStatus(TargetUpdateStatus.PENDING, tIds));
|
||||
|
||||
final Map<String, Action> targetIdsToActions = actionRepository.save(targets.stream().map(t -> {
|
||||
final Action tAction = new Action();
|
||||
final TargetWithActionType targetWithActionType = targetsWithActionMap.get(t.getControllerId());
|
||||
tAction.setActionType(targetWithActionType.getActionType());
|
||||
tAction.setForcedTime(targetWithActionType.getForceTime());
|
||||
tAction.setActive(true);
|
||||
tAction.setStatus(Status.RUNNING);
|
||||
tAction.setTarget(t);
|
||||
tAction.setDistributionSet(set);
|
||||
return tAction;
|
||||
}).collect(Collectors.toList())).stream()
|
||||
.collect(Collectors.toMap(a -> a.getTarget().getControllerId(), Function.identity()));
|
||||
|
||||
// MECS-720 create initial action status when action is created so we
|
||||
// remember the initial
|
||||
// running status because we will change the status of the action itself
|
||||
// and with this action
|
||||
// status we have a nicer action history.
|
||||
targetIdsToActions.values().forEach(action -> {
|
||||
final ActionStatus actionStatus = new ActionStatus();
|
||||
actionStatus.setAction(action);
|
||||
actionStatus.setOccurredAt(action.getCreatedAt());
|
||||
actionStatus.setStatus(Status.RUNNING);
|
||||
actionStatusRepository.save(actionStatus);
|
||||
});
|
||||
|
||||
// select updated targets in order to return them
|
||||
final DistributionSetAssignmentResult result = new DistributionSetAssignmentResult(
|
||||
targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()), targets.size(),
|
||||
controllerIDs.size() - targets.size(), Lists.newArrayList(targetIdsToActions.values()),
|
||||
targetManagement);
|
||||
|
||||
LOG.debug("assignDistribution({}) finished {}", set, result);
|
||||
|
||||
final List<SoftwareModule> softwareModules = softwareModuleRepository.findByAssignedTo(set);
|
||||
|
||||
// detaching as it is not necessary to persist the set itself
|
||||
entityManager.detach(set);
|
||||
|
||||
// send distribution set assignment event
|
||||
targets.stream().filter(t -> !!!targetIdsCancellList.contains(t.getId()))
|
||||
.forEach(t -> deploymentManagementEvents.assignDistributionSet(t,
|
||||
targetIdsToActions.get(t.getControllerId()).getId(), softwareModules));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes {@link UpdateAction}s that are no longer necessary and sends
|
||||
* cancelations to the controller.
|
||||
*
|
||||
* @param myTarget
|
||||
* to override {@link UpdateAction}s
|
||||
*/
|
||||
private Set<Long> overrideObsoleteUpdateActions(final List<Long> targetsIds) {
|
||||
|
||||
final Set<Long> cancelledTargetIds = new HashSet<Long>();
|
||||
|
||||
// Figure out if there are potential target/action combinations that
|
||||
// need to be considered
|
||||
// for cancelation
|
||||
final List<Action> activeActions = actionRepository
|
||||
.findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetRequiredMigrationStep(targetsIds,
|
||||
Action.Status.CANCELING);
|
||||
activeActions.forEach(action -> {
|
||||
action.setStatus(Status.CANCELING);
|
||||
// document that the status has been retrieved
|
||||
actionStatusRepository.save(new ActionStatus(action, Status.CANCELING, System.currentTimeMillis(),
|
||||
"manual cancelation requested"));
|
||||
deploymentManagementEvents.cancalAssignDistributionSet(action.getTarget(), action.getId());
|
||||
cancelledTargetIds.add(action.getTarget().getId());
|
||||
});
|
||||
actionRepository.save(activeActions);
|
||||
|
||||
return cancelledTargetIds;
|
||||
}
|
||||
|
||||
private DistributionSetAssignmentResult assignDistributionSetByTargetId(@NotNull final DistributionSet set,
|
||||
@NotEmpty final List<String> tIDs, final ActionType actionType, final long forcedTime) {
|
||||
return assignDistributionSetToTargets(set, tIDs.stream()
|
||||
.map(t -> new TargetWithActionType(t, actionType, forcedTime)).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal helper method used only inside service level. As a result is no
|
||||
* additional security necessary.
|
||||
*
|
||||
* @param target
|
||||
* to update
|
||||
* @param status
|
||||
* of the target
|
||||
* @param setInstalledDate
|
||||
* to set
|
||||
*
|
||||
* @return updated target
|
||||
*/
|
||||
Target updateTargetInfo(@NotNull final Target target, @NotNull final TargetUpdateStatus status,
|
||||
final boolean setInstalledDate) {
|
||||
final TargetInfo ts = target.getTargetInfo();
|
||||
ts.setUpdateStatus(status);
|
||||
|
||||
if (setInstalledDate) {
|
||||
ts.setInstallationDate(System.currentTimeMillis());
|
||||
}
|
||||
targetInfoRepository.save(ts);
|
||||
return entityManager.merge(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels given {@link Action} for given {@link Target}. The method will
|
||||
* immediately add a {@link ActionStatus.Status#CANCELED} status to the
|
||||
* action. However, it might be possible that the controller will continue
|
||||
* to work on the cancellation.
|
||||
*
|
||||
* @param action
|
||||
* to be canceled
|
||||
* @param target
|
||||
* for which the action needs cancellation
|
||||
*
|
||||
* @return generated {@link CancelAction} or <code>null</code> if not in
|
||||
* {@link Target#getActiveActions()}.
|
||||
* @throws CancelActionNotAllowedException
|
||||
* in case the given action is not active or is already a cancel
|
||||
* action
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
public Action cancelAction(@NotNull final Action action, @NotNull final Target target) {
|
||||
LOG.debug("cancelAction({}, {})", action, target);
|
||||
if (action.isCancelingOrCanceled()) {
|
||||
throw new CancelActionNotAllowedException("Actions in canceling or canceled state cannot be canceled");
|
||||
}
|
||||
final Action myAction = entityManager.merge(action);
|
||||
|
||||
if (myAction.isActive()) {
|
||||
LOG.debug("action ({}) was still active. Change to {}.", action, Status.CANCELING);
|
||||
myAction.setStatus(Status.CANCELING);
|
||||
|
||||
// document that the status has been retrieved
|
||||
actionStatusRepository.save(new ActionStatus(myAction, Status.CANCELING, System.currentTimeMillis(),
|
||||
"manual cancelation requested"));
|
||||
|
||||
deploymentManagementEvents.cancalAssignDistributionSet(target, myAction.getId());
|
||||
|
||||
return actionRepository.save(myAction);
|
||||
} else {
|
||||
throw new CancelActionNotAllowedException(
|
||||
"Action [id: " + action.getId() + "] is not active and cannot be canceled");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Action} entity for given actionId.
|
||||
*
|
||||
* @param actionId
|
||||
* to be id of the action
|
||||
* @return the corresponding {@link Action}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Action findAction(@NotNull final Long actionId) {
|
||||
return actionRepository.findOne(actionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Action} entity for given actionId with all lazy
|
||||
* attributes.
|
||||
*
|
||||
* @param actionId
|
||||
* to be id of the action
|
||||
* @return the corresponding {@link Action}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Action findActionWithDetails(@NotNull final Long actionId) {
|
||||
return actionRepository.findById(actionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s of a specific target.
|
||||
*
|
||||
* @param pageable
|
||||
* pagination parameter
|
||||
* @param target
|
||||
* of which the actions have to be searched
|
||||
* @return a paged list of actions associated with the given target
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Slice<Action> findActionsByTarget(final Pageable pageable, final Target target) {
|
||||
return actionRepository.findByTarget(pageable, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s of a specific target ordered by action ID.
|
||||
*
|
||||
* @param target
|
||||
* the target associated with the actions
|
||||
* @return a list of actions associated with the given target ordered by
|
||||
* action ID
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public List<Action> findActionsByTarget(final Target target) {
|
||||
return actionRepository.findByTarget(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s of a specific target ordered by action ID.
|
||||
*
|
||||
* @param target
|
||||
* the target associated with the actions
|
||||
* @return a list of actions associated with the given target ordered by
|
||||
* action ID
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public List<ActionWithStatusCount> findActionsWithStatusCountByTargetOrderByIdDesc(final Target target) {
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<ActionWithStatusCount> query = cb.createQuery(ActionWithStatusCount.class);
|
||||
final Root<Action> actionRoot = query.from(Action.class);
|
||||
final ListJoin<Action, ActionStatus> actionStatusJoin = actionRoot.join(Action_.actionStatus, JoinType.LEFT);
|
||||
final Join<Action, DistributionSet> actionDsJoin = actionRoot.join(Action_.distributionSet);
|
||||
|
||||
final CriteriaQuery<ActionWithStatusCount> multiselect = query.distinct(true).multiselect(
|
||||
actionRoot.get(Action_.id), actionRoot.get(Action_.actionType), actionRoot.get(Action_.active),
|
||||
actionRoot.get(Action_.forcedTime), actionRoot.get(Action_.status), actionRoot.get(Action_.createdAt),
|
||||
actionRoot.get(Action_.lastModifiedAt), actionDsJoin.get(DistributionSet_.id),
|
||||
actionDsJoin.get(DistributionSet_.name), actionDsJoin.get(DistributionSet_.version),
|
||||
cb.count(actionStatusJoin));
|
||||
multiselect.where(cb.equal(actionRoot.get(Action_.target), target));
|
||||
multiselect.orderBy(cb.desc(actionRoot.get(Action_.id)));
|
||||
multiselect.groupBy(actionRoot.get(Action_.id));
|
||||
final List<ActionWithStatusCount> resultList = entityManager.createQuery(multiselect).getResultList();
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s assigned to a specific {@link Target} and a
|
||||
* given specification.
|
||||
*
|
||||
* @param specifiction
|
||||
* the specification to narrow down the search
|
||||
* @param target
|
||||
* the target which must be assigned to the actions
|
||||
* @param pageable
|
||||
* the page request
|
||||
* @return a slice of actions assigned to the specific target and the
|
||||
* specification
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Slice<Action> findActionsByTarget(final Specification<Action> specifiction, final Target target,
|
||||
final Pageable pageable) {
|
||||
|
||||
return actionRepository.findAll(new Specification<Action>() {
|
||||
|
||||
@Override
|
||||
public Predicate toPredicate(final Root<Action> root, final CriteriaQuery<?> query,
|
||||
final CriteriaBuilder cb) {
|
||||
return cb.and(specifiction.toPredicate(root, query, cb), cb.equal(root.get(Action_.target), target));
|
||||
}
|
||||
}, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param foundTarget
|
||||
* @param pageable
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Slice<Action> findActionsByTarget(final Target foundTarget, final Pageable pageable) {
|
||||
return actionRepository.findByTarget(pageable, foundTarget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all active {@link Action}s of a specific target ordered by
|
||||
* action ID.
|
||||
*
|
||||
* @param pageable
|
||||
* the pagination parameter
|
||||
* @param target
|
||||
* the target associated with the actions
|
||||
* @return a paged list of actions associated with the given target
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Page<Action> findActiveActionsByTarget(final Pageable pageable, final Target target) {
|
||||
return actionRepository.findByActiveAndTarget(pageable, target, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all active {@link Action}s of a specific target ordered by
|
||||
* action ID.
|
||||
*
|
||||
* @param target
|
||||
* the target associated with the actions
|
||||
* @return a list of actions associated with the given target
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public List<Action> findActiveActionsByTarget(final Target target) {
|
||||
return actionRepository.findByActiveAndTarget(target, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all inactive {@link Action}s of a specific target ordered by
|
||||
* action ID.
|
||||
*
|
||||
* @param target
|
||||
* the target associated with the actions
|
||||
* @return a list of actions associated with the given target
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public List<Action> findInActiveActionsByTarget(final Target target) {
|
||||
return actionRepository.findByActiveAndTarget(target, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all inactive {@link Action}s of a specific target ordered by
|
||||
* action ID.
|
||||
*
|
||||
* @param pageable
|
||||
* the pagination parameter
|
||||
* @param target
|
||||
* the target associated with the actions
|
||||
* @return a paged list of actions associated with the given target
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Page<Action> findInActiveActionsByTarget(final Pageable pageable, final Target target) {
|
||||
return actionRepository.findByActiveAndTarget(pageable, target, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* counts all actions associated to a specific target.
|
||||
*
|
||||
* @param target
|
||||
* the target associated to the actions to count
|
||||
* @return the count value of found actions associated to the target
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Long countActionsByTarget(@NotNull final Target target) {
|
||||
return actionRepository.countByTarget(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* counts all actions associated to a specific target.
|
||||
*
|
||||
* @param spec
|
||||
* the specification to filter the count result
|
||||
* @param target
|
||||
* the target associated to the actions to count
|
||||
* @return the count value of found actions associated to the target
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Long countActionsByTarget(@NotNull final Specification<Action> spec, @NotNull final Target target) {
|
||||
return actionRepository.count(new Specification<Action>() {
|
||||
@Override
|
||||
public Predicate toPredicate(final Root<Action> root, final CriteriaQuery<?> query,
|
||||
final CriteriaBuilder cb) {
|
||||
return cb.and(spec.toPredicate(root, query, cb), cb.equal(root.get(Action_.target), target));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a {@link TargetAction} and forces the {@link TargetAction} if
|
||||
* it's not already forced.
|
||||
*
|
||||
* @param targetId
|
||||
* the ID of the target
|
||||
* @param actionId
|
||||
* the ID of the action
|
||||
* @return the updated or the found {@link TargetAction}
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
public Action forceTargetAction(final Long actionId) {
|
||||
final Action action = actionRepository.findOne(actionId);
|
||||
if (action != null && !action.isForced()) {
|
||||
action.setActionType(ActionType.FORCED);
|
||||
return actionRepository.save(action);
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieves all the {@link ActionStatus} entries of the given
|
||||
* {@link Action} and {@link Target} in the order latest first.
|
||||
*
|
||||
* @param pageReq
|
||||
* pagination parameter
|
||||
* @param action
|
||||
* to be filtered on
|
||||
* @param withMessages
|
||||
* to <code>true</code> if {@link ActionStatus#getMessages()}
|
||||
* need to be fetched.
|
||||
* @return the corresponding {@link Page} of {@link ActionStatus}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Page<ActionStatus> findActionStatusMessagesByActionInDescOrder(final Pageable pageReq, final Action action,
|
||||
final boolean withMessages) {
|
||||
if (withMessages) {
|
||||
return actionStatusRepository.getByActionOrderByIdDesc(pageReq, action);
|
||||
} else {
|
||||
return actionStatusRepository.findByActionOrderByIdDesc(pageReq, action);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
|
||||
/**
|
||||
* A bean which holds a complex result of an service operation to combine the
|
||||
* information of an assignment and how much of the assignment has been done and
|
||||
* how much of the assignments had already been existed.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class DistributionSetAssignmentResult extends AssignmentResult {
|
||||
|
||||
private final List<String> assignedTargets;
|
||||
private final List<Action> actions;
|
||||
|
||||
private final TargetManagement targetManagement;
|
||||
|
||||
/**
|
||||
*
|
||||
* Constructor.
|
||||
*
|
||||
* @param assignedTargets
|
||||
* the target objects which have been assigned to the
|
||||
* distribution set
|
||||
* @param assigned
|
||||
* count of the assigned targets
|
||||
* @param alreadyAssigned
|
||||
* the count of the already assigned targets
|
||||
* @param targetManagement
|
||||
* to retrieve the assigned targets
|
||||
* @param actions
|
||||
* of the assignment
|
||||
*
|
||||
*/
|
||||
public DistributionSetAssignmentResult(final List<String> assignedTargets, final int assigned,
|
||||
final int alreadyAssigned, final List<Action> actions, final TargetManagement targetManagement) {
|
||||
super(assigned, alreadyAssigned);
|
||||
this.assignedTargets = assignedTargets;
|
||||
this.actions = actions;
|
||||
this.targetManagement = targetManagement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the assignedTargets
|
||||
*/
|
||||
public List<Target> getAssignedTargets() {
|
||||
return targetManagement.findTargetsByControllerID(assignedTargets);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionId
|
||||
*/
|
||||
public List<Action> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
|
||||
/**
|
||||
* Holds distribution set filter parameters.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class DistributionSetFilter {
|
||||
private final Boolean isDeleted;
|
||||
private final Boolean isComplete;
|
||||
private final DistributionSetType type;
|
||||
private final String searchText;
|
||||
private final Boolean selectDSWithNoTag;
|
||||
private final Collection<String> tagNames;
|
||||
private final String assignedTargetId;
|
||||
private final String installedTargetId;
|
||||
|
||||
/**
|
||||
* Parametric constructor.
|
||||
*
|
||||
* @param builder
|
||||
* DistributionSetFilterBuilder
|
||||
*/
|
||||
public DistributionSetFilter(final DistributionSetFilterBuilder builder) {
|
||||
this.isDeleted = builder.isDeleted;
|
||||
this.isComplete = builder.isComplete;
|
||||
this.type = builder.type;
|
||||
this.searchText = builder.searchText;
|
||||
this.selectDSWithNoTag = builder.selectDSWithNoTag;
|
||||
this.tagNames = builder.tagNames;
|
||||
this.assignedTargetId = builder.assignedTargetId;
|
||||
this.installedTargetId = builder.installedTargetId;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Distribution set filter builder.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public static class DistributionSetFilterBuilder {
|
||||
private Boolean isDeleted;
|
||||
private Boolean isComplete;
|
||||
private DistributionSetType type;
|
||||
private String searchText;
|
||||
private Boolean selectDSWithNoTag;
|
||||
private Collection<String> tagNames;
|
||||
private String assignedTargetId;
|
||||
private String installedTargetId;
|
||||
|
||||
/**
|
||||
* Build filter.
|
||||
*
|
||||
* @return DistributionSetFilter
|
||||
*/
|
||||
public DistributionSetFilter build() {
|
||||
return new DistributionSetFilter(this);
|
||||
}
|
||||
|
||||
public DistributionSetFilterBuilder setIsDeleted(final Boolean isDeleted) {
|
||||
this.isDeleted = isDeleted;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DistributionSetFilterBuilder setIsComplete(final Boolean isComplete) {
|
||||
this.isComplete = isComplete;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DistributionSetFilterBuilder setType(final DistributionSetType type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DistributionSetFilterBuilder setSearchText(final String searchText) {
|
||||
this.searchText = searchText;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DistributionSetFilterBuilder setSelectDSWithNoTag(final Boolean selectDSWithNoTag) {
|
||||
this.selectDSWithNoTag = selectDSWithNoTag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DistributionSetFilterBuilder setTagNames(final Collection<String> tagNames) {
|
||||
this.tagNames = tagNames;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DistributionSetFilterBuilder setAssignedTargetId(final String assignedTargetId) {
|
||||
this.assignedTargetId = assignedTargetId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DistributionSetFilterBuilder setInstalledTargetId(final String installedTargetId) {
|
||||
this.installedTargetId = installedTargetId;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Boolean getIsDeleted() {
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
public Boolean getIsComplete() {
|
||||
return isComplete;
|
||||
}
|
||||
|
||||
public DistributionSetType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getSearchText() {
|
||||
return searchText;
|
||||
}
|
||||
|
||||
public Boolean getSelectDSWithNoTag() {
|
||||
return selectDSWithNoTag;
|
||||
}
|
||||
|
||||
public Collection<String> getTagNames() {
|
||||
return tagNames;
|
||||
}
|
||||
|
||||
public String getAssignedTargetId() {
|
||||
return assignedTargetId;
|
||||
}
|
||||
|
||||
public String getInstalledTargetId() {
|
||||
return installedTargetId;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.DsMetadataCompositeKey;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link DistributionSetMetadata} repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface DistributionSetMetadataRepository
|
||||
extends PagingAndSortingRepository<DistributionSetMetadata, DsMetadataCompositeKey>,
|
||||
JpaSpecificationExecutor<DistributionSetMetadata> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link DistributionSet} repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface DistributionSetRepository
|
||||
extends BaseEntityRepository<DistributionSet, Long>, JpaSpecificationExecutor<DistributionSet> {
|
||||
|
||||
/**
|
||||
* Finds {@link DistributionSet}s by assigned {@link Tag}.
|
||||
*
|
||||
* @param tag
|
||||
* to be found
|
||||
* @return list of found {@link DistributionSet}s
|
||||
*/
|
||||
@Query(value = "Select Distinct ds from DistributionSet ds join ds.tags dst where dst = :tag")
|
||||
List<DistributionSet> findByTag(@Param("tag") final DistributionSetTag tag);
|
||||
|
||||
/**
|
||||
* deletes the {@link DistributionSet}s with the given IDs.
|
||||
*
|
||||
* @param ids
|
||||
* to be deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("update DistributionSet d set d.deleted = 1 where d.id in :ids")
|
||||
void deleteDistributionSet(@Param("ids") Long... ids);
|
||||
|
||||
/**
|
||||
* deletes {@link DistributionSet}s by the given IDs.
|
||||
*
|
||||
* @param ids
|
||||
* List of IDs of {@link DistributionSet}s to be deleted
|
||||
* @return number of affected/deleted records
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("DELETE FROM DistributionSet d WHERE d.id IN ?1")
|
||||
int deleteByIdIn(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* Finds {@link DistributionSet}s where given {@link SoftwareModule} is
|
||||
* assigned.
|
||||
*
|
||||
* @param module
|
||||
* to search for
|
||||
* @return {@link List} of found {@link DistributionSet}s
|
||||
*/
|
||||
List<DistributionSet> findByModules(SoftwareModule module);
|
||||
|
||||
/**
|
||||
* Finds {@link DistributionSet}s based on given ID if they are not assigned
|
||||
* yet to an {@link UpdateAction}, i.e. unused.
|
||||
*
|
||||
* @param ids
|
||||
* to searcgh for
|
||||
* @return
|
||||
*/
|
||||
@Query("select ac.distributionSet.id from Action ac where ac.distributionSet.id in :ids")
|
||||
List<Long> findAssignedDistributionSetsById(@Param("ids") Long... ids);
|
||||
|
||||
/**
|
||||
* Saves all given {@link DistributionSet}s.
|
||||
*
|
||||
* @param entities
|
||||
* @return the saved entities
|
||||
* @throws IllegalArgumentException
|
||||
* in case the given entity is (@literal null}.
|
||||
*
|
||||
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
|
||||
*/
|
||||
@Override
|
||||
<S extends DistributionSet> List<S> save(Iterable<S> entities);
|
||||
|
||||
/**
|
||||
* Finds the distribution set for a specific action.
|
||||
*
|
||||
* @param action
|
||||
* the action associated with the distribution set to find
|
||||
* @return the distribution set associated with the given action
|
||||
*/
|
||||
@Query("select DISTINCT d from DistributionSet d join fetch d.modules m join d.actions a where a = :action")
|
||||
DistributionSet findByAction(@Param("action") Action action);
|
||||
|
||||
/**
|
||||
* Counts {@link DistributionSet} instances of given type in the repository.
|
||||
*
|
||||
* @param type
|
||||
* to search for
|
||||
* @return number of found {@link DistributionSet}s
|
||||
*/
|
||||
long countByType(DistributionSetType type);
|
||||
|
||||
/**
|
||||
* Counts {@link DistributionSet} with given
|
||||
* {@link DistributionSet#getName()} and
|
||||
* {@link DistributionSet#getVersion()}.
|
||||
*
|
||||
* @param name
|
||||
* to search for
|
||||
* @param version
|
||||
* to search for
|
||||
* @return number of found {@link DistributionSet}s
|
||||
*/
|
||||
long countByNameAndVersion(String name, String version);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
|
||||
/**
|
||||
* Result object for {@link DistributionSetTag} assigments.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class DistributionSetTagAssigmentResult extends AssignmentResult {
|
||||
|
||||
private final int unassigned;
|
||||
private final List<DistributionSet> assignedDs;
|
||||
private final List<DistributionSet> unassignedDs;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param alreadyAssigned
|
||||
* number of already assigned/ignored elements
|
||||
* @param assigned
|
||||
* number of newly assigned elements
|
||||
* @param unassigned
|
||||
* number of newly assigned elements
|
||||
* @param assignedDs
|
||||
* {@link List} of assigned {@link DistributionSet}s.
|
||||
* @param unassignedDs
|
||||
* {@link List} of unassigned {@link DistributionSet}s.
|
||||
*/
|
||||
public DistributionSetTagAssigmentResult(final int alreadyAssigned, final int assigned, final int unassigned,
|
||||
final List<DistributionSet> assignedDs, final List<DistributionSet> unassignedDs) {
|
||||
super(assigned, alreadyAssigned);
|
||||
this.unassigned = unassigned;
|
||||
this.assignedDs = assignedDs;
|
||||
this.unassignedDs = unassignedDs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the unassigned
|
||||
*/
|
||||
public int getUnassigned() {
|
||||
return unassigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the assignedDs
|
||||
*/
|
||||
public List<DistributionSet> getAssignedDs() {
|
||||
return assignedDs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the unassignedDs
|
||||
*/
|
||||
public List<DistributionSet> getUnassignedDs() {
|
||||
return unassignedDs;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link TargetTag} repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface DistributionSetTagRepository extends BaseEntityRepository<DistributionSetTag, Long> {
|
||||
/**
|
||||
* deletes the {@link DistributionSet} with the given name.
|
||||
*
|
||||
* @param tagName
|
||||
* to be deleted
|
||||
* @return 1 if tag was deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
Long deleteByName(final String tagName);
|
||||
|
||||
/**
|
||||
* find {@link DistributionSetTag} by its name.
|
||||
*
|
||||
* @param tagName
|
||||
* to filter on
|
||||
* @return the {@link DistributionSetTag} if found, otherwise null
|
||||
*/
|
||||
DistributionSetTag findByNameEquals(final String tagName);
|
||||
|
||||
/**
|
||||
* Returns all instances of the type.
|
||||
*
|
||||
* @return all entities
|
||||
*/
|
||||
@Override
|
||||
List<DistributionSetTag> findAll();
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link PagingAndSortingRepository} for {@link DistributionSetType}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface DistributionSetTypeRepository
|
||||
extends BaseEntityRepository<DistributionSetType, Long>, JpaSpecificationExecutor<DistributionSetType> {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param isDeleted
|
||||
* to <code>true</code> if only soft deleted entries of
|
||||
* <code>false</code> if undeleted ones
|
||||
* @return list of found {@link DistributionSetType}s
|
||||
*/
|
||||
Page<DistributionSetType> findByDeleted(Pageable pageable, boolean isDeleted);
|
||||
|
||||
/**
|
||||
* @param isDeleted
|
||||
* to <code>true</code> if only marked as deleted have to be
|
||||
* count or all undeleted.
|
||||
* @return number of {@link DistributionSetType}s in the repository.
|
||||
*/
|
||||
Long countByDeleted(boolean isDeleted);
|
||||
|
||||
/**
|
||||
* Counts all distribution set type where a specific software module type is
|
||||
* assigned to.
|
||||
*
|
||||
* @param softwareModuleType
|
||||
* the software module type to count the distribution set type
|
||||
* which has this software module type assigned
|
||||
* @return the number of {@link DistributionSetType}s in the repository
|
||||
* assigned to the given software module type
|
||||
*/
|
||||
Long countByElementsSmType(SoftwareModuleType softwareModuleType);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* Custom repository implementation as standard spring repository fails as of
|
||||
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=415027 .
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
public class EclipseLinkTargetInfoRepository implements TargetInfoRepository {
|
||||
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Override
|
||||
@Modifying
|
||||
public void setTargetUpdateStatus(final TargetUpdateStatus status, final List<Long> targets) {
|
||||
final Query query = entityManager.createQuery(
|
||||
"update TargetInfo ti set ti.updateStatus = :status where ti.targetId in :targets and ti.updateStatus != :status");
|
||||
query.setParameter("targets", targets);
|
||||
query.setParameter("status", status);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Modifying
|
||||
@CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true)
|
||||
public <S extends TargetInfo> S save(final S entity) {
|
||||
|
||||
if (entity.isNew()) {
|
||||
entityManager.persist(entity);
|
||||
return entity;
|
||||
} else {
|
||||
return entityManager.merge(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Modifying
|
||||
@CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true)
|
||||
public void deleteByTargetIdIn(final Collection<Long> targetIDs) {
|
||||
final javax.persistence.Query query = entityManager
|
||||
.createQuery("DELETE FROM TargetInfo ti where ti.targetId IN :target");
|
||||
query.setParameter("target", targetIDs);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Repository for {@link ExternalArtifactProvider}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface ExternalArtifactProviderRepository extends BaseEntityRepository<ExternalArtifactProvider, Long> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.ExternalArtifact;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link ExternalArtifact} repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface ExternalArtifactRepository extends BaseEntityRepository<ExternalArtifact, Long> {
|
||||
|
||||
/**
|
||||
* Searches for external artifact for a base software module.
|
||||
*
|
||||
* @param pageReq
|
||||
* Pageable
|
||||
* @param swId
|
||||
* software module id
|
||||
*
|
||||
* @return Page<ExternalArtifact>
|
||||
*/
|
||||
Page<ExternalArtifact> findBySoftwareModuleId(Pageable pageReq, final Long swId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.LocalArtifact;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link LocalArtifact} repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface LocalArtifactRepository extends BaseEntityRepository<LocalArtifact, Long> {
|
||||
/**
|
||||
* Searches for a {@link LocalArtifact} based on given gridFsFileName.
|
||||
*
|
||||
* @param gridFsFileName
|
||||
* to search
|
||||
* @return list of {@link LocalArtifact}s.
|
||||
*/
|
||||
List<LocalArtifact> findByGridFsFileName(String gridFsFileName);
|
||||
|
||||
/**
|
||||
* Searches for a {@link LocalArtifact} based on given gridFsFileName.
|
||||
*
|
||||
* @param gridFsFileName
|
||||
* to search
|
||||
* @return {@link LocalArtifact} the first in the result list
|
||||
*/
|
||||
LocalArtifact findFirstByGridFsFileName(String gridFsFileName);
|
||||
|
||||
/**
|
||||
* Searches for a {@link LocalArtifact} based user provided filename at
|
||||
* upload.
|
||||
*
|
||||
* @param filename
|
||||
* to search
|
||||
* @return list of {@link LocalArtifact}.
|
||||
*/
|
||||
List<LocalArtifact> findByFilename(String filename);
|
||||
|
||||
/**
|
||||
* Searches for local artifact for a base software module.
|
||||
*
|
||||
* @param pageReq
|
||||
* Pageable
|
||||
* @param swId
|
||||
* software module id
|
||||
*
|
||||
* @return Page<LocalArtifact>
|
||||
*/
|
||||
Page<LocalArtifact> findBySoftwareModuleId(Pageable pageReq, final Long swId);
|
||||
|
||||
/**
|
||||
* Searches for a {@link LocalArtifact} based user provided filename at
|
||||
* upload and selected software module id.
|
||||
*
|
||||
* @param filename
|
||||
* to search
|
||||
* @param softwareModuleId
|
||||
* selected software module id
|
||||
* @return list of {@link LocalArtifact}.
|
||||
*/
|
||||
List<LocalArtifact> findByFilenameAndSoftwareModuleId(final String filename, final Long softwareModuleId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* Workaround as spring data does not provide a {@link Slice} based
|
||||
* {@link JpaRepository#findAll()}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Repository
|
||||
public class NoCountPagingRepository {
|
||||
|
||||
@Autowired
|
||||
protected EntityManager em;
|
||||
|
||||
/**
|
||||
* Searches without the need for an extra count query.
|
||||
*
|
||||
* @param spec
|
||||
* to search for
|
||||
* @param pageable
|
||||
* information
|
||||
* @param domainClass
|
||||
* of the {@link Entity}
|
||||
*
|
||||
* @return {@link Slice} of data
|
||||
*
|
||||
* @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll(org.springframework
|
||||
* .data.jpa.domain.Specification,
|
||||
* org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
public <T, I extends Serializable> Slice<T> findAll(final Specification<T> spec, final Pageable pageable,
|
||||
final Class<T> domainClass) {
|
||||
final SimpleJpaNoCountRepository<T, I> noCountDao = new SimpleJpaNoCountRepository<T, I>(domainClass, em);
|
||||
return noCountDao.findAll(spec, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches without the need for an extra count query.
|
||||
*
|
||||
* @param pageable
|
||||
* information
|
||||
* @param domainClass
|
||||
* of the {@link Entity}
|
||||
*
|
||||
* @return {@link Slice} of data
|
||||
*
|
||||
* @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll(org.springframework
|
||||
* .data.jpa.domain.Specification,
|
||||
* org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
public <T, I extends Serializable> Slice<T> findAll(final Pageable pageable, final Class<T> domainClass) {
|
||||
final SimpleJpaNoCountRepository<T, I> noCountDao = new SimpleJpaNoCountRepository<T, I>(domainClass, em);
|
||||
return noCountDao.findAll(pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Repository implementation with disabled count query.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param <T>
|
||||
* entity type
|
||||
* @param <I>
|
||||
* key or ID type
|
||||
*/
|
||||
public static class SimpleJpaNoCountRepository<T, I extends Serializable> extends SimpleJpaRepository<T, I> {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param domainClass
|
||||
* of the {@link Entity}
|
||||
* @param em
|
||||
* {@link EntityManager} instance for the queries
|
||||
*/
|
||||
public SimpleJpaNoCountRepository(final Class<T> domainClass, final EntityManager em) {
|
||||
super(domainClass, em);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.data.jpa.repository.support.SimpleJpaRepository#
|
||||
* readPage(javax.persistence .TypedQuery,
|
||||
* org.springframework.data.domain.Pageable,
|
||||
* org.springframework.data.jpa.domain.Specification)
|
||||
*/
|
||||
@Override
|
||||
protected Page<T> readPage(final TypedQuery<T> query, final Pageable pageable, final Specification<T> spec) {
|
||||
query.setFirstResult(pageable.getOffset());
|
||||
query.setMaxResults(pageable.getPageSize());
|
||||
|
||||
final List<T> content = query.getResultList();
|
||||
|
||||
return new PageImpl<T>(content, pageable, content.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,631 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.YearMonth;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.eclipse.hawkbit.report.model.DataReportSeries;
|
||||
import org.eclipse.hawkbit.report.model.DataReportSeriesItem;
|
||||
import org.eclipse.hawkbit.report.model.InnerOuterDataReportSeries;
|
||||
import org.eclipse.hawkbit.report.model.ListReportSeries;
|
||||
import org.eclipse.hawkbit.report.model.SeriesTime;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo_;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Target_;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* Service layer for generating SP reportings.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
@ConfigurationProperties
|
||||
public class ReportManagement {
|
||||
|
||||
@Value("${spring.jpa.database}")
|
||||
private String databaseType;
|
||||
|
||||
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM");
|
||||
|
||||
private static final String H2_TARGET_CREATED_SQL_TEMPLATE = "SELECT TO_CHAR( DATEADD('second', target0_.created_at / 1000, DATE '1970-01-01'), '%s') AS col_0_0_, count(target0_.controller_id) AS col_1_0_ from sp_target target0_ WHERE TO_CHAR(DATEADD('second', target0_.created_at / 1000, DATE '1970-01-01'),'%s') BETWEEN TO_CHAR('%s', '%s') and TO_CHAR('%s', '%s') AND UPPER(target0_.tenant)=UPPER('%s') GROUP BY TO_CHAR(DATEADD('second', target0_.created_at / 1000, DATE '1970-01-01'), '%s')";
|
||||
|
||||
private static final String H2_CONTROLLER_FRRDBACK_SQL_TEMPLATE = "SELECT TO_CHAR(DATEADD('second', action_.created_at / 1000, DATE '1970-01-01'), '%s') AS col_0_0_, count(action_.id) AS col_1_0_ FROM sp_action action_ WHERE TO_CHAR(DATEADD('second', action_.created_at / 1000, DATE '1970-01-01'), '%s') BETWEEN TO_CHAR('%s', '%s') AND TO_CHAR('%s', '%s') AND UPPER(action_.tenant)=UPPER('%s') GROUP BY TO_CHAR(DATEADD('second', action_.created_at / 1000, DATE '1970-01-01'), '%s')";
|
||||
|
||||
private static final String MYSQL_TARGET_CREATED_SQL_TEMPLATE = "SELECT DATE_FORMAT(FROM_UNIXTIME(target0_.created_at / 1000), '%s') AS col_0_0_, COUNT(target0_.controller_id) AS col_1_0_ FROM sp_target target0_ WHERE DATE_FORMAT(FROM_UNIXTIME(target0_.created_at / 1000),'%s') BETWEEN DATE_FORMAT('%s', '%s') AND DATE_FORMAT('%s', '%s') AND UPPER(target0_.tenant)=UPPER('%s') GROUP BY DATE_FORMAT(FROM_UNIXTIME(target0_.created_at / 1000), '%s')";
|
||||
|
||||
private static final String MYSQL_CONTROLLER_FRRDBACK_SQL_TEMPLATE = "SELECT DATE_FORMAT(FROM_UNIXTIME(action_.created_at / 1000), '%s') AS col_0_0_, COUNT(action_.id) as col_1_0_ FROM sp_action action_ WHERE DATE_FORMAT(FROM_UNIXTIME(action_.created_at / 1000),'%s') BETWEEN DATE_FORMAT('%s', '%s') AND DATE_FORMAT('%s', '%s') AND UPPER(action_.tenant)=UPPER('%s') GROUP BY DATE_FORMAT(FROM_UNIXTIME(action_.created_at / 1000), '%s')";
|
||||
|
||||
private static final String MYSQL_DB_TYPE = "MYSQL";
|
||||
|
||||
private static final String H2_DB_TYPE = "H2";
|
||||
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
private TenantAware tenantAware;
|
||||
|
||||
/**
|
||||
* Generates a report of all targets of their current update status count.
|
||||
* For each {@link TargetUpdateStatus} an total count of targets which are
|
||||
* in this status currently.
|
||||
*
|
||||
* @return a data report series which contains the target count for each
|
||||
* target update status
|
||||
*/
|
||||
@Cacheable("targetStatus")
|
||||
public DataReportSeries<TargetUpdateStatus> targetStatus() {
|
||||
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Object[]> query = cb.createQuery(Object[].class);
|
||||
final Root<Target> targetRoot = query.from(Target.class);
|
||||
final Join<Target, TargetInfo> targetInfo = targetRoot.join(Target_.targetInfo);
|
||||
final Expression<Long> countColumn = cb.count(targetInfo.get(TargetInfo_.targetId));
|
||||
final CriteriaQuery<Object[]> multiselect = query
|
||||
.multiselect(targetInfo.get(TargetInfo_.updateStatus), countColumn)
|
||||
.groupBy(targetInfo.get(TargetInfo_.updateStatus))
|
||||
.orderBy(cb.desc(targetInfo.get(TargetInfo_.updateStatus)));
|
||||
|
||||
// | col1 | col2 |
|
||||
// | U_STATUS | COUNT |
|
||||
final List<Object[]> resultList = entityManager.createQuery(multiselect).getResultList();
|
||||
|
||||
final List<DataReportSeriesItem<TargetUpdateStatus>> reportSeriesItems = resultList.stream()
|
||||
.map(r -> new DataReportSeriesItem<TargetUpdateStatus>((TargetUpdateStatus) r[0], (Long) r[1]))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new DataReportSeries<>("Target Status Overview", reportSeriesItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a report of the top x distribution set assigned usage as a list
|
||||
* of {@link InnerOuterDataReportSeries} which is ideal for generate a donut
|
||||
* chart out of it. The inner series contains the distribution set names and
|
||||
* total count usage. The outer series contains each version usage and its
|
||||
* usage count. {@code inner: ds1:5 -> outer: vers 0.0.0:3, vers 1.0.0:2}
|
||||
* {@code inner: ds2:1 -> outer: vers 0.0.1:1}
|
||||
*
|
||||
* The top x entries are seperated within the series, the rest of the
|
||||
* distribution sets usage are summarized to a "misc" series.
|
||||
*
|
||||
* @param topXEntries
|
||||
* the top entries which should be shown, the rest distribution
|
||||
* set entries are summarized as "misc"
|
||||
* @return a list of inner and outer series of distribution set usage
|
||||
*/
|
||||
@Cacheable("distributionUsageAssigned")
|
||||
public List<InnerOuterDataReportSeries<String>> distributionUsageAssigned(final int topXEntries) {
|
||||
|
||||
// top X entries distribution usage
|
||||
final CriteriaBuilder cbTopX = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Object[]> queryTopX = cbTopX.createQuery(Object[].class);
|
||||
final Root<DistributionSet> rootTopX = queryTopX.from(DistributionSet.class);
|
||||
final ListJoin<DistributionSet, Target> joinTopX = rootTopX.join(DistributionSet_.assignedToTargets,
|
||||
JoinType.LEFT);
|
||||
final Expression<Long> countColumn = cbTopX.count(joinTopX);
|
||||
// top x usage query
|
||||
final CriteriaQuery<Object[]> groupBy = queryTopX
|
||||
.multiselect(rootTopX.get(DistributionSet_.name), rootTopX.get(DistributionSet_.version), countColumn)
|
||||
.where(cbTopX.equal(rootTopX.get(DistributionSet_.deleted), false))
|
||||
.groupBy(rootTopX.get(DistributionSet_.name), rootTopX.get(DistributionSet_.version))
|
||||
.orderBy(cbTopX.desc(countColumn), cbTopX.asc(rootTopX.get(DistributionSet_.name)));
|
||||
// | col1 | col2 | col3 |
|
||||
// | NAME | VER | COUNT |
|
||||
final List<Object[]> resultListTop = entityManager.createQuery(groupBy).getResultList();
|
||||
// end of top X entries distribution usage
|
||||
|
||||
return mapDistirbutionUsageResultToDataReport(topXEntries, resultListTop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a report of the top x distribution set installed usage as a
|
||||
* list of {@link InnerOuterDataReportSeries} which is ideal for generate a
|
||||
* donut chart out of it. The inner series contains the distribution set
|
||||
* names and total count usage. The outer series contains each version usage
|
||||
* and its usage count.
|
||||
* {@code inner: ds1:5 -> outer: vers 0.0.0:3, vers 1.0.0:2}
|
||||
* {@code inner: ds2:1 -> outer: vers 0.0.1:1}
|
||||
*
|
||||
* The top x entries are seperated within the series, the rest of the
|
||||
* distribution sets usage are summarized to a "misc" series.
|
||||
*
|
||||
* @param topXEntries
|
||||
* the top entries which should be shown, the rest distribution
|
||||
* set entries are summarized as "misc"
|
||||
* @return a list of inner and outer series of distribution set usage
|
||||
*/
|
||||
@Cacheable("distributionUsageInstalled")
|
||||
public List<InnerOuterDataReportSeries<String>> distributionUsageInstalled(final int topXEntries) {
|
||||
// top X entries distribution usage
|
||||
final CriteriaBuilder cbTopX = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Object[]> queryTopX = cbTopX.createQuery(Object[].class);
|
||||
final Root<DistributionSet> rootTopX = queryTopX.from(DistributionSet.class);
|
||||
final ListJoin<DistributionSet, TargetInfo> joinTopX = rootTopX.join(DistributionSet_.installedAtTargets,
|
||||
JoinType.LEFT);
|
||||
final Expression<Long> countColumn = cbTopX.count(joinTopX);
|
||||
// top x usage query
|
||||
final CriteriaQuery<Object[]> groupBy = queryTopX
|
||||
.multiselect(rootTopX.get(DistributionSet_.name), rootTopX.get(DistributionSet_.version), countColumn)
|
||||
.where(cbTopX.equal(rootTopX.get(DistributionSet_.deleted), false))
|
||||
.groupBy(rootTopX.get(DistributionSet_.name), rootTopX.get(DistributionSet_.version))
|
||||
.orderBy(cbTopX.desc(countColumn), cbTopX.asc(rootTopX.get(DistributionSet_.name)));
|
||||
// | col1 | col2 | col3 |
|
||||
// | NAME | VER | COUNT |
|
||||
final List<Object[]> resultListTop = entityManager.createQuery(groupBy).getResultList();
|
||||
// end of top X entries distribution usage
|
||||
|
||||
return mapDistirbutionUsageResultToDataReport(topXEntries, resultListTop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates report for target created over period.
|
||||
*
|
||||
* @param dateType
|
||||
* {@link PerMonth}
|
||||
* @param from
|
||||
* start date
|
||||
* @param to
|
||||
* end date
|
||||
* @return <T> DataReportSeries<T> ListReportSeries list of target created
|
||||
* count
|
||||
*/
|
||||
@Cacheable("targetsCreatedOverPeriod")
|
||||
public <T> DataReportSeries<T> targetsCreatedOverPeriod(final DateType<T> dateType, final LocalDateTime from,
|
||||
final LocalDateTime to) {
|
||||
final Query createNativeQuery = entityManager
|
||||
.createNativeQuery(getTargetsCreatedQueryTemplate(dateType, from, to));
|
||||
final List<Object[]> resultList = createNativeQuery.getResultList();
|
||||
|
||||
final List<DataReportSeriesItem<T>> reportItems = resultList.stream()
|
||||
.map(r -> new DataReportSeriesItem<>(dateType.format((String) r[0]), ((Number) r[1]).longValue()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final DataReportSeries<T> report = new DataReportSeries<>("CreatedTargets", reportItems);
|
||||
return report;
|
||||
}
|
||||
|
||||
private String getTargetsCreatedQueryTemplate(final DateType<?> dateType, final LocalDateTime from,
|
||||
final LocalDateTime to) {
|
||||
switch (databaseType) {
|
||||
case H2_DB_TYPE:
|
||||
return String.format(H2_TARGET_CREATED_SQL_TEMPLATE, dateTimeFormatToSqlFormat(dateType),
|
||||
dateTimeFormatToSqlFormat(dateType), from.format(DATE_FORMAT), dateTimeFormatToSqlFormat(dateType),
|
||||
to.format(DATE_FORMAT), dateTimeFormatToSqlFormat(dateType), tenantAware.getCurrentTenant(),
|
||||
dateTimeFormatToSqlFormat(dateType));
|
||||
case MYSQL_DB_TYPE:
|
||||
return String.format(MYSQL_TARGET_CREATED_SQL_TEMPLATE, dateTimeFormatToSqlFormat(dateType),
|
||||
dateTimeFormatToSqlFormat(dateType), from.toString(), dateTimeFormatToSqlFormat(dateType),
|
||||
to.toString(), dateTimeFormatToSqlFormat(dateType), tenantAware.getCurrentTenant(),
|
||||
dateTimeFormatToSqlFormat(dateType));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getFeedbackReceivedQueryTemplate(final DateType<?> dateType, final LocalDateTime from,
|
||||
final LocalDateTime to) {
|
||||
switch (databaseType) {
|
||||
case H2_DB_TYPE:
|
||||
return String.format(H2_CONTROLLER_FRRDBACK_SQL_TEMPLATE, dateTimeFormatToSqlFormat(dateType),
|
||||
dateTimeFormatToSqlFormat(dateType), from.format(DATE_FORMAT), dateTimeFormatToSqlFormat(dateType),
|
||||
to.format(DATE_FORMAT), dateTimeFormatToSqlFormat(dateType), tenantAware.getCurrentTenant(),
|
||||
dateTimeFormatToSqlFormat(dateType));
|
||||
case MYSQL_DB_TYPE:
|
||||
return String.format(MYSQL_CONTROLLER_FRRDBACK_SQL_TEMPLATE, dateTimeFormatToSqlFormat(dateType),
|
||||
dateTimeFormatToSqlFormat(dateType), from.toString(), dateTimeFormatToSqlFormat(dateType),
|
||||
to.toString(), dateTimeFormatToSqlFormat(dateType), tenantAware.getCurrentTenant(),
|
||||
dateTimeFormatToSqlFormat(dateType));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates report for feedback over period.
|
||||
*
|
||||
* @param dateType
|
||||
* {@link PerMonth}
|
||||
* @param from
|
||||
* start date
|
||||
* @param to
|
||||
* end date
|
||||
* @return <T> DataReportSeries<T> ListReportSeries list of action status
|
||||
* count
|
||||
*/
|
||||
@Cacheable("feedbackReceivedOverTime")
|
||||
public <T> DataReportSeries<T> feedbackReceivedOverTime(final DateType<T> dateType, final LocalDateTime from,
|
||||
final LocalDateTime to) {
|
||||
final Query createNativeQuery = entityManager
|
||||
.createNativeQuery(getFeedbackReceivedQueryTemplate(dateType, from, to));
|
||||
final List<Object[]> resultList = createNativeQuery.getResultList();
|
||||
|
||||
final List<DataReportSeriesItem<T>> reportItems = resultList.stream()
|
||||
.map(r -> new DataReportSeriesItem<>(dateType.format((String) r[0]), ((Number) r[1]).longValue()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final DataReportSeries<T> report = new DataReportSeries<>("FeedbackRecieved", reportItems);
|
||||
return report;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a report as a {@link ListReportSeries} targets polled based on
|
||||
* the {@link TargetStatus#getLastTargetQuery()} within an hour, day, week,
|
||||
* month, year, more than a year, never.
|
||||
*
|
||||
* The order of the numbers within the {@link DataReportSeries} is the order
|
||||
* hour, day, week, month, year, more than a year, never.
|
||||
*
|
||||
* @return a {@link DataReportSeries} which contains the number of targets
|
||||
* which have not been polled in the last hour, day, ... year,more
|
||||
* than a year, never.
|
||||
*
|
||||
*/
|
||||
@Cacheable("targetsLastPoll")
|
||||
public DataReportSeries<SeriesTime> targetsLastPoll() {
|
||||
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
final LocalDateTime beforeHour = now.minusHours(1);
|
||||
final LocalDateTime beforeDay = now.minusDays(1);
|
||||
final LocalDateTime beforeWeek = now.minusWeeks(1);
|
||||
final LocalDateTime beforeMonth = now.minusMonths(1);
|
||||
final LocalDateTime beforeYear = now.minusYears(1);
|
||||
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final List<DataReportSeriesItem<SeriesTime>> resultList = new ArrayList<>();
|
||||
|
||||
// hours
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.HOUR,
|
||||
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, beforeHour, now)).getSingleResult()));
|
||||
// days
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.DAY, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeDay, beforeHour)).getSingleResult()));
|
||||
// weeks
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.WEEK, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeWeek, beforeDay)).getSingleResult()));
|
||||
// months
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.MONTH, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeMonth, beforeWeek)).getSingleResult()));
|
||||
// years
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.YEAR, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeYear, beforeMonth)).getSingleResult()));
|
||||
// years
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.MORE_THAN_YEAR,
|
||||
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, null, beforeYear)).getSingleResult()));
|
||||
// never
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.NEVER,
|
||||
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, null, null)).getSingleResult()));
|
||||
|
||||
return new DataReportSeries<>("TargetLastPoll", resultList);
|
||||
}
|
||||
|
||||
private CriteriaQuery<Long> createCountSelectTargetsLastPoll(final CriteriaBuilder cb, final LocalDateTime from,
|
||||
final LocalDateTime to) {
|
||||
|
||||
Long start = null;
|
||||
Long end = null;
|
||||
if (from != null) {
|
||||
start = from.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
}
|
||||
if (to != null) {
|
||||
end = to.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
// count select statement
|
||||
final CriteriaQuery<Long> countSelect = cb.createQuery(Long.class);
|
||||
final Root<Target> countSelectRoot = countSelect.from(Target.class);
|
||||
final Join<Target, TargetInfo> targetInfoJoin = countSelectRoot.join(Target_.targetInfo);
|
||||
countSelect.select(cb.count(countSelectRoot));
|
||||
if (start != null && end != null) {
|
||||
countSelect.where(cb.between(targetInfoJoin.get(TargetInfo_.lastTargetQuery), start, end));
|
||||
} else if (from == null && to != null) {
|
||||
countSelect.where(cb.lessThanOrEqualTo(targetInfoJoin.get(TargetInfo_.lastTargetQuery), end));
|
||||
} else {
|
||||
countSelect.where(cb.isNull(targetInfoJoin.get(TargetInfo_.lastTargetQuery)));
|
||||
}
|
||||
return countSelect;
|
||||
}
|
||||
|
||||
private List<InnerOuterDataReportSeries<String>> mapDistirbutionUsageResultToDataReport(final int topXEntries,
|
||||
final List<Object[]> resultListTop) {
|
||||
final List<InnerOuterDataReportSeries<String>> innerOuterReport = new ArrayList<>();
|
||||
final Map<DSName, InnerOuter> map = new LinkedHashMap<>();
|
||||
|
||||
int topXCounter = 0;
|
||||
|
||||
for (final Object[] objects : resultListTop) {
|
||||
|
||||
final boolean containsInnerOuter = map.containsKey(new DSName((String) objects[0]));
|
||||
final String name = containsInnerOuter || topXCounter < topXEntries ? (String) objects[0] : null;
|
||||
final DSName dsName = new DSName(name);
|
||||
final String version = containsInnerOuter || topXCounter < topXEntries ? (String) objects[1] : null;
|
||||
final Long count = (Long) objects[2];
|
||||
|
||||
InnerOuter innerouter = map.get(dsName);
|
||||
if (innerouter == null) {
|
||||
topXCounter++;
|
||||
innerouter = new InnerOuter(dsName);
|
||||
map.put(new DSName(name), innerouter);
|
||||
}
|
||||
innerouter.addOuter(new DSName(version), count);
|
||||
}
|
||||
|
||||
for (final InnerOuter inner : map.values()) {
|
||||
final List<DataReportSeriesItem<String>> outerReportItems = new ArrayList<>();
|
||||
|
||||
if (inner.name.getName() != null) {
|
||||
for (final InnerOuter outer : inner.outer) {
|
||||
outerReportItems.add(outer.toItem());
|
||||
}
|
||||
} else {
|
||||
outerReportItems.add(new DataReportSeriesItem<String>("misc", inner.count));
|
||||
}
|
||||
|
||||
innerOuterReport.add(new InnerOuterDataReportSeries<String>(
|
||||
new DataReportSeries<>("DS-Name", Collections.singletonList(inner.toItem())),
|
||||
new DataReportSeries<>("DS-Version", outerReportItems)));
|
||||
}
|
||||
|
||||
return innerOuterReport;
|
||||
}
|
||||
|
||||
private final class InnerOuter {
|
||||
final DSName name;
|
||||
long count;
|
||||
final List<InnerOuter> outer;
|
||||
|
||||
private InnerOuter(final DSName idName) {
|
||||
name = idName;
|
||||
outer = new ArrayList<>();
|
||||
}
|
||||
|
||||
private InnerOuter(final DSName idName, final long count) {
|
||||
name = idName;
|
||||
this.count = count;
|
||||
outer = new ArrayList<>();
|
||||
}
|
||||
|
||||
private void addOuter(final DSName idName, final long count) {
|
||||
outer.add(new InnerOuter(idName, count));
|
||||
this.count += count;
|
||||
}
|
||||
|
||||
private DataReportSeriesItem<String> toItem() {
|
||||
return new DataReportSeriesItem<String>(name.getName() != null ? name.getName() : "misc", count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Object contains the name and the id of an entity.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
private static final class DSName {
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* the ID of an entity
|
||||
* @param name
|
||||
* the name of an entity
|
||||
*/
|
||||
private DSName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
private String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (name == null ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) { // NOSONAR - as this is
|
||||
// generated
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final DSName other = (DSName) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!name.equals(other.name)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DSName [name=" + name + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private String dateTimeFormatToSqlFormat(final DateType<?> datatype) {
|
||||
switch (databaseType) {
|
||||
case H2_DB_TYPE:
|
||||
return datatype.h2Format();
|
||||
case MYSQL_DB_TYPE:
|
||||
return datatype.mySqlFormat();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return DateTypes.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public static final class DateTypes implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final PerMonth PER_MONTH = new PerMonth();
|
||||
|
||||
private DateTypes() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PerMonth
|
||||
*/
|
||||
public static PerMonth perMonth() {
|
||||
return PER_MONTH;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data base format.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public interface DateType<T> {
|
||||
/**
|
||||
* @param s
|
||||
* @return T
|
||||
*/
|
||||
T format(String s);
|
||||
|
||||
/**
|
||||
* h2 format.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String h2Format();
|
||||
|
||||
/**
|
||||
* mysql format.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String mySqlFormat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the date format based on DB H2 or mySql.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public static final class PerMonth implements DateType<LocalDate>, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String DATE_PATTERN = "yyyy-MM";
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.hawkbit.server.repository.ReportManagement.DateType#
|
||||
* format(java. lang.String)
|
||||
*/
|
||||
@Override
|
||||
public LocalDate format(final String s) {
|
||||
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_PATTERN);
|
||||
final YearMonth ym = YearMonth.parse(s, formatter);
|
||||
return ym.atDay(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.hawkbit.server.repository.ReportManagement.DateType#
|
||||
* h2Format()
|
||||
*/
|
||||
@Override
|
||||
public String h2Format() {
|
||||
return DATE_PATTERN;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.hawkbit.server.repository.ReportManagement.DateType#
|
||||
* mySqlFormat( )
|
||||
*/
|
||||
@Override
|
||||
public String mySqlFormat() {
|
||||
return "%Y-%m";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,944 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.CustomSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.model.LocalArtifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata_;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule_;
|
||||
import org.eclipse.hawkbit.repository.model.SwMetadataCompositeKey;
|
||||
import org.eclipse.hawkbit.repository.specifications.SoftwareModuleSpecification;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.SliceImpl;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.domain.Specifications;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Business facade for managing the deployable {@link SoftwareModule}s.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
public class SoftwareManagement {
|
||||
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
private DistributionSetRepository distributionSetRepository;
|
||||
|
||||
@Autowired
|
||||
private DistributionSetTypeRepository distributionSetTypeRepository;
|
||||
|
||||
@Autowired
|
||||
private SoftwareModuleRepository softwareModuleRepository;
|
||||
|
||||
@Autowired
|
||||
private SoftwareModuleMetadataRepository softwareModuleMetadataRepository;
|
||||
|
||||
@Autowired
|
||||
private SoftwareModuleTypeRepository softwareModuleTypeRepository;
|
||||
|
||||
@Autowired
|
||||
private NoCountPagingRepository criteriaNoCountDao;
|
||||
|
||||
@Autowired
|
||||
private AuditorAware<String> auditorProvider;
|
||||
|
||||
@Autowired
|
||||
private ArtifactManagement artifactManagement;
|
||||
|
||||
/**
|
||||
* Updates existing {@link SoftwareModule}. Updateable values are
|
||||
* {@link SoftwareModule#getDescription()}
|
||||
* {@link SoftwareModule#getVendor()}.
|
||||
*
|
||||
* @param sm
|
||||
* to update
|
||||
*
|
||||
* @return the saved {@link Entity}.
|
||||
*
|
||||
* @throws NullPointerException
|
||||
* of {@link SoftwareModule#getId()} is <code>null</code>
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
public SoftwareModule updateSoftwareModule(@NotNull final SoftwareModule sm) {
|
||||
checkNotNull(sm.getId());
|
||||
|
||||
final SoftwareModule module = softwareModuleRepository.findOne(sm.getId());
|
||||
|
||||
if (null == sm.getDescription() || !sm.getDescription().equals(module.getDescription())) {
|
||||
module.setDescription(sm.getDescription());
|
||||
}
|
||||
if (null == sm.getVendor() || !sm.getVendor().equals(module.getVendor())) {
|
||||
module.setVendor(sm.getVendor());
|
||||
}
|
||||
return softwareModuleRepository.save(module);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates existing {@link SoftwareModuleType}. Updatable value is
|
||||
* {@link SoftwareModuleType#getDescription()} and
|
||||
* {@link SoftwareModuleType#getColour()}.
|
||||
*
|
||||
* @param sm
|
||||
* to update
|
||||
* @return updated {@link Entity}
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
public SoftwareModuleType updateSoftwareModuleType(@NotNull final SoftwareModuleType sm) {
|
||||
checkNotNull(sm.getId());
|
||||
|
||||
final SoftwareModuleType type = softwareModuleTypeRepository.findOne(sm.getId());
|
||||
|
||||
if (sm.getDescription() != null && !sm.getDescription().equals(type.getDescription())) {
|
||||
type.setDescription(sm.getDescription());
|
||||
}
|
||||
if (sm.getColour() != null && !sm.getColour().equals(type.getColour())) {
|
||||
type.setColour(sm.getColour());
|
||||
}
|
||||
return softwareModuleTypeRepository.save(type);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param swModule
|
||||
* SoftwareModule to create
|
||||
* @return SoftwareModule
|
||||
* @throws EntityAlreadyExistsException
|
||||
* if a given entity already exists
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
public SoftwareModule createSoftwareModule(@NotNull final SoftwareModule swModule) {
|
||||
if (null != swModule.getId()) {
|
||||
throw new EntityAlreadyExistsException();
|
||||
}
|
||||
return softwareModuleRepository.save(swModule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link SoftwareModule}s in the repository.
|
||||
*
|
||||
* @param swModules
|
||||
* {@link SoftwareModule}s to create
|
||||
* @return SoftwareModule
|
||||
* @throws EntityAlreadyExistsException
|
||||
* if a given entity already exists
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
public List<SoftwareModule> createSoftwareModule(@NotNull final Iterable<SoftwareModule> swModules) {
|
||||
swModules.forEach(swModule -> {
|
||||
if (null != swModule.getId()) {
|
||||
throw new EntityAlreadyExistsException();
|
||||
}
|
||||
});
|
||||
|
||||
return softwareModuleRepository.save(swModules);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieves the {@link SoftwareModule}s by their {@link SoftwareModuleType}
|
||||
* .
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param type
|
||||
* to be filtered on
|
||||
* @return the found {@link SoftwareModule}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Slice<SoftwareModule> findSoftwareModulesByType(@NotNull final Pageable pageable,
|
||||
@NotNull final SoftwareModuleType type) {
|
||||
|
||||
final List<Specification<SoftwareModule>> specList = new ArrayList<Specification<SoftwareModule>>();
|
||||
|
||||
Specification<SoftwareModule> spec = SoftwareModuleSpecification.equalType(type);
|
||||
specList.add(spec);
|
||||
|
||||
spec = SoftwareModuleSpecification.isDeletedFalse();
|
||||
specList.add(spec);
|
||||
|
||||
return findSwModuleByCriteriaAPI(pageable, specList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts {@link SoftwareModule}s with given {@link SoftwareModuleType}.
|
||||
*
|
||||
* @param type
|
||||
* to count
|
||||
* @return number of found {@link SoftwareModule}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Long countSoftwareModulesByType(@NotNull final SoftwareModuleType type) {
|
||||
|
||||
final List<Specification<SoftwareModule>> specList = new ArrayList<Specification<SoftwareModule>>();
|
||||
|
||||
Specification<SoftwareModule> spec = SoftwareModuleSpecification.equalType(type);
|
||||
specList.add(spec);
|
||||
|
||||
spec = SoftwareModuleSpecification.isDeletedFalse();
|
||||
specList.add(spec);
|
||||
|
||||
return countSwModuleByCriteriaAPI(specList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds {@link SoftwareModule} by given id.
|
||||
*
|
||||
* @param id
|
||||
* to search for
|
||||
* @return the found {@link SoftwareModule}s or <code>null</code> if not
|
||||
* found.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_CONTROLLER)
|
||||
public SoftwareModule findSoftwareModuleById(@NotNull final Long id) {
|
||||
return artifactManagement.findSoftwareModuleById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieves {@link SoftwareModule}s by their name AND version.
|
||||
*
|
||||
* @param name
|
||||
* of the {@link SoftwareModule}
|
||||
* @param version
|
||||
* of the {@link SoftwareModule}
|
||||
* @return the found {@link SoftwareModule}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public List<SoftwareModule> findSoftwareModuleByNameAndVersion(@NotEmpty final String name,
|
||||
@NotEmpty final String version) {
|
||||
|
||||
return softwareModuleRepository.findByNameAndVersion(name, version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given {@link SoftwareModule} {@link Entity}.
|
||||
*
|
||||
* @param bsm
|
||||
* is the {@link SoftwareModule} to be deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
||||
public void deleteSoftwareModule(@NotNull final SoftwareModule bsm) {
|
||||
|
||||
deleteSoftwareModules(Sets.newHashSet(bsm.getId()));
|
||||
}
|
||||
|
||||
private boolean isUnassigned(final SoftwareModule bsmMerged) {
|
||||
return distributionSetRepository.findByModules(bsmMerged).isEmpty();
|
||||
}
|
||||
|
||||
private Slice<SoftwareModule> findSwModuleByCriteriaAPI(@NotNull final Pageable pageable,
|
||||
@NotEmpty final List<Specification<SoftwareModule>> specList) {
|
||||
|
||||
Specifications<SoftwareModule> specs = Specifications.where(specList.get(0));
|
||||
if (specList.size() > 1) {
|
||||
for (final Specification<SoftwareModule> s : specList.subList(1, specList.size())) {
|
||||
specs = specs.and(s);
|
||||
}
|
||||
}
|
||||
|
||||
return criteriaNoCountDao.findAll(specs, pageable, SoftwareModule.class);
|
||||
}
|
||||
|
||||
private Long countSwModuleByCriteriaAPI(@NotEmpty final List<Specification<SoftwareModule>> specList) {
|
||||
Specifications<SoftwareModule> specs = Specifications.where(specList.get(0));
|
||||
if (specList.size() > 1) {
|
||||
for (final Specification<SoftwareModule> s : specList.subList(1, specList.size())) {
|
||||
specs = specs.and(s);
|
||||
}
|
||||
}
|
||||
|
||||
return softwareModuleRepository.count(specs);
|
||||
}
|
||||
|
||||
private void deleteGridFsArtifacts(final SoftwareModule swModule) {
|
||||
for (final LocalArtifact localArtifact : swModule.getLocalArtifacts()) {
|
||||
artifactManagement.deleteGridFsArtifact(localArtifact);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes {@link SoftwareModule}s which is any if the given ids.
|
||||
*
|
||||
* @param ids
|
||||
* of the Software Moduels to be deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
||||
public void deleteSoftwareModules(@NotNull final Iterable<Long> ids) {
|
||||
final List<SoftwareModule> swModulesToDelete = softwareModuleRepository.findByIdIn(ids);
|
||||
final Set<Long> assignedModuleIds = new HashSet<>();
|
||||
swModulesToDelete.forEach(swModule -> {
|
||||
|
||||
// delete binary data of artifacts
|
||||
deleteGridFsArtifacts(swModule);
|
||||
|
||||
if (isUnassigned(swModule)) {
|
||||
|
||||
softwareModuleRepository.delete(swModule);
|
||||
|
||||
} else {
|
||||
|
||||
assignedModuleIds.add(swModule.getId());
|
||||
}
|
||||
});
|
||||
|
||||
if (!assignedModuleIds.isEmpty()) {
|
||||
String currentUser = null;
|
||||
if (auditorProvider != null) {
|
||||
currentUser = auditorProvider.getCurrentAuditor();
|
||||
}
|
||||
softwareModuleRepository.deleteSoftwareModule(System.currentTimeMillis(), currentUser,
|
||||
assignedModuleIds.toArray(new Long[0]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all software modules. Deleted ones are filtered.
|
||||
*
|
||||
* @param pageable
|
||||
* pagination parameter
|
||||
* @return the found {@link SoftwareModule}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Slice<SoftwareModule> findSoftwareModulesAll(@NotNull final Pageable pageable) {
|
||||
|
||||
final List<Specification<SoftwareModule>> specList = new ArrayList<Specification<SoftwareModule>>();
|
||||
|
||||
Specification<SoftwareModule> spec = SoftwareModuleSpecification.isDeletedFalse();
|
||||
specList.add(spec);
|
||||
|
||||
spec = new Specification<SoftwareModule>() {
|
||||
@Override
|
||||
public Predicate toPredicate(final Root<SoftwareModule> root, final CriteriaQuery<?> query,
|
||||
final CriteriaBuilder cb) {
|
||||
if (!query.getResultType().isAssignableFrom(Long.class)) {
|
||||
root.fetch(SoftwareModule_.type);
|
||||
}
|
||||
return cb.conjunction();
|
||||
}
|
||||
};
|
||||
|
||||
specList.add(spec);
|
||||
|
||||
return findSwModuleByCriteriaAPI(pageable, specList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count all {@link SoftwareModule}s in the repository that are not marked
|
||||
* as deleted.
|
||||
*
|
||||
* @return number of {@link SoftwareModule}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Long countSoftwareModulesAll() {
|
||||
|
||||
final List<Specification<SoftwareModule>> specList = new ArrayList<Specification<SoftwareModule>>();
|
||||
|
||||
final Specification<SoftwareModule> spec = SoftwareModuleSpecification.isDeletedFalse();
|
||||
specList.add(spec);
|
||||
|
||||
return countSwModuleByCriteriaAPI(specList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves software module including details (
|
||||
* {@link SoftwareModule#getArtifacts()}).
|
||||
*
|
||||
* @param id
|
||||
* parameter
|
||||
* @param isDeleted
|
||||
* parameter
|
||||
* @return the found {@link SoftwareModule}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public SoftwareModule findSoftwareModuleWithDetails(@NotNull final Long id) {
|
||||
return artifactManagement.findSoftwareModuleWithDetails(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all {@link SoftwareModule}s with a given specification.
|
||||
*
|
||||
* @param spec
|
||||
* the specification to filter the software modules
|
||||
* @param pageable
|
||||
* pagination parameter
|
||||
* @return the found {@link SoftwareModule}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Page<SoftwareModule> findSoftwareModulesByPredicate(@NotNull final Specification<SoftwareModule> spec,
|
||||
@NotNull final Pageable pageable) {
|
||||
return softwareModuleRepository.findAll(spec, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all {@link SoftwareModuleType}s with a given specification.
|
||||
*
|
||||
* @param spec
|
||||
* the specification to filter the software modules types
|
||||
* @param pageable
|
||||
* pagination parameter
|
||||
* @return the found {@link SoftwareModuleType}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Page<SoftwareModuleType> findSoftwareModuleTypesByPredicate(
|
||||
@NotNull final Specification<SoftwareModuleType> spec, @NotNull final Pageable pageable) {
|
||||
return softwareModuleTypeRepository.findAll(spec, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all software modules with a given list of ids
|
||||
* {@link SoftwareModule#getId()}.
|
||||
*
|
||||
* @param ids
|
||||
* to search for
|
||||
* @return {@link List} of found {@link SoftwareModule}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public List<SoftwareModule> findSoftwareModulesById(@NotEmpty final List<Long> ids) {
|
||||
return softwareModuleRepository.findByIdIn(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter {@link SoftwareModule}s with given
|
||||
* {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()}
|
||||
* and {@link SoftwareModule#getType()} that are not marked as deleted.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameter
|
||||
* @param searchText
|
||||
* to be filtered as "like" on {@link SoftwareModule#getName()}
|
||||
* @param type
|
||||
* to be filtered as "like" on {@link SoftwareModule#getType()}
|
||||
* @return the page of found {@link SoftwareModule}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Slice<SoftwareModule> findSoftwareModuleByFilters(@NotNull final Pageable pageable, final String searchText,
|
||||
final SoftwareModuleType type) {
|
||||
|
||||
final List<Specification<SoftwareModule>> specList = new ArrayList<Specification<SoftwareModule>>();
|
||||
|
||||
Specification<SoftwareModule> spec = SoftwareModuleSpecification.isDeletedFalse();
|
||||
specList.add(spec);
|
||||
|
||||
if (!Strings.isNullOrEmpty(searchText)) {
|
||||
spec = SoftwareModuleSpecification.likeNameOrVersion(searchText);
|
||||
specList.add(spec);
|
||||
}
|
||||
|
||||
if (null != type) {
|
||||
spec = SoftwareModuleSpecification.equalType(type);
|
||||
specList.add(spec);
|
||||
}
|
||||
|
||||
spec = new Specification<SoftwareModule>() {
|
||||
@Override
|
||||
public Predicate toPredicate(final Root<SoftwareModule> root, final CriteriaQuery<?> query,
|
||||
final CriteriaBuilder cb) {
|
||||
if (!query.getResultType().isAssignableFrom(Long.class)) {
|
||||
root.fetch(SoftwareModule_.type);
|
||||
}
|
||||
return cb.conjunction();
|
||||
}
|
||||
};
|
||||
|
||||
specList.add(spec);
|
||||
|
||||
return findSwModuleByCriteriaAPI(pageable, specList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter {@link SoftwareModule}s with given
|
||||
* {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()}
|
||||
* and {@link SoftwareModule#getType()} that are not marked as deleted.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameter
|
||||
* @param orderByDistributionId
|
||||
* the ID of distribution set to be order by
|
||||
* @param searchText
|
||||
* to be filtered as "like" on {@link SoftwareModule#getName()}
|
||||
* @param type
|
||||
* to be filtered as "like" on {@link SoftwareModule#getType()}
|
||||
* @return the page of found {@link SoftwareModule}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Slice<CustomSoftwareModule> findSoftwareModuleOrderByDistribution(@NotNull final Pageable pageable,
|
||||
@NotNull final Long orderByDistributionId, final String searchText, final SoftwareModuleType type) {
|
||||
|
||||
final List<CustomSoftwareModule> resultList = new ArrayList<>();
|
||||
final int pageSize = pageable.getPageSize();
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
|
||||
// get the assigned software modules
|
||||
final CriteriaQuery<SoftwareModule> assignedQuery = cb.createQuery(SoftwareModule.class);
|
||||
final Root<SoftwareModule> assignedRoot = assignedQuery.from(SoftwareModule.class);
|
||||
assignedQuery.distinct(true);
|
||||
final ListJoin<SoftwareModule, DistributionSet> assignedDsJoin = assignedRoot.join(SoftwareModule_.assignedTo);
|
||||
// build the specifications and then to predicates necessary by the
|
||||
// given filters
|
||||
final Predicate[] specPredicate = specificationsToPredicate(buildSpecificationList(searchText, type),
|
||||
assignedRoot, assignedQuery, cb,
|
||||
cb.equal(assignedDsJoin.get(DistributionSet_.id), orderByDistributionId));
|
||||
// if we have some predicates then add it to the where clause of the
|
||||
// multiselect
|
||||
assignedQuery.where(specPredicate);
|
||||
assignedQuery.orderBy(cb.asc(assignedRoot.get(SoftwareModule_.name)),
|
||||
cb.asc(assignedRoot.get(SoftwareModule_.version)));
|
||||
// don't page the assigned query on database, we need all assigned
|
||||
// software modules to filter
|
||||
// them out in the unassigned query
|
||||
final List<SoftwareModule> assignedSoftwareModules = entityManager.createQuery(assignedQuery).getResultList();
|
||||
// map result
|
||||
if (pageable.getOffset() < assignedSoftwareModules.size()) {
|
||||
assignedSoftwareModules
|
||||
.subList(pageable.getOffset(), Math.min(assignedSoftwareModules.size(), pageable.getPageSize()))
|
||||
.forEach(sw -> resultList.add(new CustomSoftwareModule(sw, true)));
|
||||
}
|
||||
|
||||
if (assignedSoftwareModules.size() >= pageSize) {
|
||||
return new SliceImpl<>(resultList);
|
||||
}
|
||||
|
||||
// get the unassigned software modules
|
||||
final CriteriaQuery<SoftwareModule> unassignedQuery = cb.createQuery(SoftwareModule.class);
|
||||
unassignedQuery.distinct(true);
|
||||
final Root<SoftwareModule> unassignedRoot = unassignedQuery.from(SoftwareModule.class);
|
||||
|
||||
Predicate[] unassignedSpec = null;
|
||||
if (!assignedSoftwareModules.isEmpty()) {
|
||||
unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot,
|
||||
unassignedQuery, cb, cb.not(unassignedRoot.get(SoftwareModule_.id)
|
||||
.in(assignedSoftwareModules.stream().map(sw -> sw.getId()).collect(Collectors.toList()))));
|
||||
} else {
|
||||
unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot,
|
||||
unassignedQuery, cb);
|
||||
}
|
||||
|
||||
unassignedQuery.where(unassignedSpec);
|
||||
unassignedQuery.orderBy(cb.asc(unassignedRoot.get(SoftwareModule_.name)),
|
||||
cb.asc(unassignedRoot.get(SoftwareModule_.version)));
|
||||
final List<SoftwareModule> unassignedSoftwareModules = entityManager.createQuery(unassignedQuery)
|
||||
.setFirstResult(Math.max(0, pageable.getOffset() - assignedSoftwareModules.size()))
|
||||
.setMaxResults(pageSize).getResultList();
|
||||
// map result
|
||||
unassignedSoftwareModules.forEach(sw -> resultList.add(new CustomSoftwareModule(sw, false)));
|
||||
|
||||
return new SliceImpl<>(resultList);
|
||||
}
|
||||
|
||||
private List<Specification<SoftwareModule>> buildSpecificationList(final String searchText,
|
||||
final SoftwareModuleType type) {
|
||||
final List<Specification<SoftwareModule>> specList = new ArrayList<Specification<SoftwareModule>>();
|
||||
if (!Strings.isNullOrEmpty(searchText)) {
|
||||
specList.add(SoftwareModuleSpecification.likeNameOrVersion(searchText));
|
||||
}
|
||||
if (type != null) {
|
||||
specList.add(SoftwareModuleSpecification.equalType(type));
|
||||
}
|
||||
specList.add(SoftwareModuleSpecification.isDeletedFalse());
|
||||
return specList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param specifications
|
||||
*/
|
||||
private Predicate[] specificationsToPredicate(final List<Specification<SoftwareModule>> specifications,
|
||||
final Root<SoftwareModule> root, final CriteriaQuery<?> query, final CriteriaBuilder cb,
|
||||
final Predicate... additionalPredicates) {
|
||||
final List<Predicate> predicates = new ArrayList<>();
|
||||
specifications.forEach(spec -> predicates.add(spec.toPredicate(root, query, cb)));
|
||||
for (final Predicate predicate : additionalPredicates) {
|
||||
predicates.add(predicate);
|
||||
}
|
||||
return predicates.toArray(new Predicate[predicates.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts {@link SoftwareModule}s with given
|
||||
* {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()}
|
||||
* and {@link SoftwareModule#getType()} that are not marked as deleted.
|
||||
*
|
||||
* @param searchText
|
||||
* to search for in name and version
|
||||
* @param type
|
||||
* to filter the result
|
||||
* @return number of found {@link SoftwareModule}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Long countSoftwareModuleByFilters(final String searchText, final SoftwareModuleType type) {
|
||||
|
||||
final List<Specification<SoftwareModule>> specList = new ArrayList<Specification<SoftwareModule>>();
|
||||
|
||||
Specification<SoftwareModule> spec = SoftwareModuleSpecification.isDeletedFalse();
|
||||
specList.add(spec);
|
||||
|
||||
if (!Strings.isNullOrEmpty(searchText)) {
|
||||
spec = SoftwareModuleSpecification.likeNameOrVersion(searchText);
|
||||
specList.add(spec);
|
||||
}
|
||||
|
||||
if (null != type) {
|
||||
spec = SoftwareModuleSpecification.equalType(type);
|
||||
specList.add(spec);
|
||||
}
|
||||
|
||||
return countSwModuleByCriteriaAPI(specList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pageable
|
||||
* parameter
|
||||
* @return all {@link SoftwareModuleType}s in the repository.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Page<SoftwareModuleType> findSoftwareModuleTypesAll(@NotNull final Pageable pageable) {
|
||||
return softwareModuleTypeRepository.findByDeleted(pageable, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of {@link SoftwareModuleType}s in the repository.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Long countSoftwareModuleTypesAll() {
|
||||
return softwareModuleTypeRepository.countByDeleted(false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* to search for
|
||||
* @return {@link SoftwareModuleType} in the repository with given
|
||||
* {@link SoftwareModuleType#getKey()}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public SoftwareModuleType findSoftwareModuleTypeByKey(@NotNull final String key) {
|
||||
return softwareModuleTypeRepository.findByKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
* to search for
|
||||
* @return {@link SoftwareModuleType} in the repository with given
|
||||
* {@link SoftwareModuleType#getId()}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public SoftwareModuleType findSoftwareModuleTypeById(@NotNull final Long id) {
|
||||
return softwareModuleTypeRepository.findOne(id);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* to search for
|
||||
* @return all {@link SoftwareModuleType}s in the repository with given
|
||||
* {@link SoftwareModuleType#getName()}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public SoftwareModuleType findSoftwareModuleTypeByName(@NotNull final String name) {
|
||||
return softwareModuleTypeRepository.findByName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link SoftwareModuleType}.
|
||||
*
|
||||
* @param type
|
||||
* to create
|
||||
* @return created {@link Entity}
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
public SoftwareModuleType createSoftwareModuleType(@NotNull final SoftwareModuleType type) {
|
||||
if (type.getId() != null) {
|
||||
throw new EntityAlreadyExistsException("Given type contains an Id!");
|
||||
}
|
||||
|
||||
return softwareModuleTypeRepository.save(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates multiple {@link SoftwareModuleType}s.
|
||||
*
|
||||
* @param types
|
||||
* to create
|
||||
* @return created {@link Entity}
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
public List<SoftwareModuleType> createSoftwareModuleTypes(@NotNull final Collection<SoftwareModuleType> types) {
|
||||
return types.stream().map(type -> createSoftwareModuleType(type)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes or markes as delete in case the type is in use.
|
||||
*
|
||||
* @param type
|
||||
* to delete
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
||||
public void deleteSoftwareModuleType(@NotNull final SoftwareModuleType type) {
|
||||
|
||||
if (softwareModuleRepository.countByType(type) > 0
|
||||
|| distributionSetTypeRepository.countByElementsSmType(type) > 0) {
|
||||
final SoftwareModuleType toDelete = entityManager.merge(type);
|
||||
toDelete.setDeleted(true);
|
||||
softwareModuleTypeRepository.save(toDelete);
|
||||
} else {
|
||||
softwareModuleTypeRepository.delete(type.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pageable
|
||||
* the page request to page the result set
|
||||
* @param set
|
||||
* to search for
|
||||
* @return all {@link SoftwareModule}s that are assigned to given
|
||||
* {@link DistributionSet}.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Page<SoftwareModule> findSoftwareModuleByAssignedTo(@NotNull final Pageable pageable,
|
||||
@NotNull final DistributionSet set) {
|
||||
return softwareModuleRepository.findByAssignedTo(pageable, set);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pageable
|
||||
* the page request to page the result set
|
||||
* @param set
|
||||
* to search for
|
||||
* @param type
|
||||
* to filter
|
||||
* @return all {@link SoftwareModule}s that are assigned to given
|
||||
* {@link DistributionSet} filtered by {@link SoftwareModuleType}.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Page<SoftwareModule> findSoftwareModuleByAssignedToAndType(@NotNull final Pageable pageable,
|
||||
@NotNull final DistributionSet set, @NotNull final SoftwareModuleType type) {
|
||||
return softwareModuleRepository.findByAssignedToAndType(pageable, set, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates or updates a single software module meta data entry.
|
||||
*
|
||||
* @param metadata
|
||||
* the meta data entry to create or update
|
||||
* @return the updated or created software module meta data entry
|
||||
* @throws EntityAlreadyExistsException
|
||||
* in case the meta data entry already exists for the specific
|
||||
* key
|
||||
*/
|
||||
@Transactional
|
||||
@Modifying
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
public SoftwareModuleMetadata createSoftwareModuleMetadata(@NotNull final SoftwareModuleMetadata metadata) {
|
||||
if (softwareModuleMetadataRepository.exists(metadata.getId())) {
|
||||
throwMetadataKeyAlreadyExists(metadata.getId().getKey());
|
||||
}
|
||||
// merge base software module so optLockRevision gets updated and audit
|
||||
// log written because
|
||||
// modifying metadata is modifying the base software module itself for
|
||||
// auditing purposes.
|
||||
entityManager.merge(metadata.getSoftwareModule()).setLastModifiedAt(-1L);
|
||||
return softwareModuleMetadataRepository.save(metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a list of software module meta data entries.
|
||||
*
|
||||
* @param metadata
|
||||
* the meta data entries to create or update
|
||||
* @return the updated or created software module meta data entries
|
||||
* @throws EntityAlreadyExistsException
|
||||
* in case one of the meta data entry already exists for the
|
||||
* specific key
|
||||
*/
|
||||
@Transactional
|
||||
@Modifying
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
public List<SoftwareModuleMetadata> createSoftwareModuleMetadata(
|
||||
@NotEmpty final Collection<SoftwareModuleMetadata> metadata) {
|
||||
for (final SoftwareModuleMetadata softwareModuleMetadata : metadata) {
|
||||
checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(softwareModuleMetadata.getId());
|
||||
}
|
||||
metadata.forEach(m -> entityManager.merge(m.getSoftwareModule()).setLastModifiedAt(-1L));
|
||||
return softwareModuleMetadataRepository.save(metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* updates a distribution set meta data value if corresponding entry exists.
|
||||
*
|
||||
* @param metadata
|
||||
* the meta data entry to be updated
|
||||
* @return the updated meta data entry
|
||||
* @throws EntityNotFoundException
|
||||
* in case the meta data entry does not exists and cannot be
|
||||
* updated
|
||||
*/
|
||||
@Transactional
|
||||
@Modifying
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
public SoftwareModuleMetadata updateSoftwareModuleMetadata(@NotNull final SoftwareModuleMetadata metadata) {
|
||||
// check if exists otherwise throw entity not found exception
|
||||
findOne(metadata.getId());
|
||||
// touch it to update the lock revision because we are modifying the
|
||||
// software module
|
||||
// indirectly
|
||||
entityManager.merge(metadata.getSoftwareModule()).setLastModifiedAt(-1L);
|
||||
return softwareModuleMetadataRepository.save(metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes a software module meta data entry.
|
||||
*
|
||||
* @param id
|
||||
* the ID of the software module meta data to delete
|
||||
*/
|
||||
@Transactional
|
||||
@Modifying
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
public void deleteSoftwareModuleMetadata(@NotNull final SwMetadataCompositeKey id) {
|
||||
softwareModuleMetadataRepository.delete(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* finds all meta data by the given software module id.
|
||||
*
|
||||
* @param swId
|
||||
* the software module id to retrieve the meta data from
|
||||
* @param pageable
|
||||
* the page request to page the result
|
||||
* @return a paged result of all meta data entries for a given software
|
||||
* module id
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Page<SoftwareModuleMetadata> findSoftwareModuleMetadataBySoftwareModuleId(@NotNull final Long swId,
|
||||
@NotNull final Pageable pageable) {
|
||||
return softwareModuleMetadataRepository.findBySoftwareModuleId(swId, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* finds all meta data by the given software module id.
|
||||
*
|
||||
* @param softwareModuleId
|
||||
* the software module id to retrieve the meta data from
|
||||
* @param spec
|
||||
* the specification to filter the result
|
||||
* @param pageable
|
||||
* the page request to page the result
|
||||
* @return a paged result of all meta data entries for a given software
|
||||
* module id
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Page<SoftwareModuleMetadata> findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId,
|
||||
@NotNull final Specification<SoftwareModuleMetadata> spec, @NotNull final Pageable pageable) {
|
||||
return softwareModuleMetadataRepository.findAll(new Specification<SoftwareModuleMetadata>() {
|
||||
@Override
|
||||
public Predicate toPredicate(final Root<SoftwareModuleMetadata> root, final CriteriaQuery<?> query,
|
||||
final CriteriaBuilder cb) {
|
||||
|
||||
return cb.and(cb.equal(root.get(SoftwareModuleMetadata_.softwareModule).get(SoftwareModule_.id),
|
||||
softwareModuleId), spec.toPredicate(root, query, cb));
|
||||
}
|
||||
}, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* finds a single software module meta data by its id.
|
||||
*
|
||||
* @param id
|
||||
* the id of the software module meta data containing the meta
|
||||
* data key and the ID of the software module
|
||||
* @return the found SoftwareModuleMetadata or {@code null} if not exits
|
||||
* @throws EntityNotFoundException
|
||||
* in case the meta data does not exists for the given key
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public SoftwareModuleMetadata findOne(@NotNull final SwMetadataCompositeKey id) {
|
||||
final SoftwareModuleMetadata findOne = softwareModuleMetadataRepository.findOne(id);
|
||||
if (findOne == null) {
|
||||
throw new EntityNotFoundException("Metadata with key '" + id.getKey() + "' does not exist");
|
||||
}
|
||||
return findOne;
|
||||
}
|
||||
|
||||
private void checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(final SwMetadataCompositeKey metadataId) {
|
||||
if (softwareModuleMetadataRepository.exists(metadataId)) {
|
||||
throw new EntityAlreadyExistsException(
|
||||
"Metadata entry with key '" + metadataId.getKey() + "' already exists");
|
||||
}
|
||||
}
|
||||
|
||||
private void throwMetadataKeyAlreadyExists(final String metadataKey) {
|
||||
throw new EntityAlreadyExistsException("Metadata entry with key '" + metadataKey + "' already exists");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SwMetadataCompositeKey;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link SoftwareModuleMetadata} repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface SoftwareModuleMetadataRepository
|
||||
extends PagingAndSortingRepository<SoftwareModuleMetadata, SwMetadataCompositeKey>,
|
||||
JpaSpecificationExecutor<SoftwareModuleMetadata> {
|
||||
|
||||
/**
|
||||
* Saves all given entities.
|
||||
*
|
||||
* @param entities
|
||||
* @return the saved entities
|
||||
* @throws IllegalArgumentException
|
||||
* in case the given entity is (@literal null}.
|
||||
*/
|
||||
@Override
|
||||
<S extends SoftwareModuleMetadata> List<S> save(Iterable<S> entities);
|
||||
|
||||
/**
|
||||
* finds all software module meta data of the given software module id.
|
||||
*
|
||||
* @param swId
|
||||
* the ID of the software module to retrieve the meta data
|
||||
* @param pageable
|
||||
* the page request to page the result set
|
||||
* @return the paged result of all meta data of an given software module id
|
||||
*/
|
||||
Page<SoftwareModuleMetadata> findBySoftwareModuleId(final Long swId, Pageable pageable);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link SoftwareModule} repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface SoftwareModuleRepository
|
||||
extends BaseEntityRepository<SoftwareModule, Long>, JpaSpecificationExecutor<SoftwareModule> {
|
||||
|
||||
/**
|
||||
* Counts all {@link SoftwareModule}s based on the given {@link Type}.
|
||||
*
|
||||
* @param type
|
||||
* to count for
|
||||
* @return number of {@link SoftwareModule}s
|
||||
*/
|
||||
Long countByType(SoftwareModuleType type);
|
||||
|
||||
/**
|
||||
* Retrieves {@link SoftwareModule}s by filtering on name AND version.
|
||||
*
|
||||
* @param name
|
||||
* to be filtered on
|
||||
* @param version
|
||||
* to be filtered on
|
||||
* @return the found {@link SoftwareModule}s with the given name AND verion
|
||||
*/
|
||||
List<SoftwareModule> findByNameAndVersion(String name, String version);
|
||||
|
||||
/**
|
||||
* deletes the {@link SoftwareModule}s with the given IDs.
|
||||
*
|
||||
* @param modifiedAt
|
||||
* current timestamp
|
||||
* @param modifiedBy
|
||||
* user name of current auditor
|
||||
* @param ids
|
||||
* to be deleted
|
||||
*
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("UPDATE SoftwareModule b SET b.deleted = 1, b.lastModifiedAt = :lastModifiedAt, b.lastModifiedBy = :lastModifiedBy WHERE b.id IN :ids")
|
||||
void deleteSoftwareModule(@Param("lastModifiedAt") Long modifiedAt, @Param("lastModifiedBy") String modifiedBy,
|
||||
@Param("ids") final Long... ids);
|
||||
|
||||
/**
|
||||
* @param pageable
|
||||
* the page request to page the result set
|
||||
* @param set
|
||||
* to search for
|
||||
* @return all {@link SoftwareModule}s that are assigned to given
|
||||
* {@link DistributionSet}.
|
||||
*/
|
||||
Page<SoftwareModule> findByAssignedTo(Pageable pageable, DistributionSet set);
|
||||
|
||||
/**
|
||||
* @param set
|
||||
* to search for
|
||||
* @return all {@link SoftwareModule}s that are assigned to given
|
||||
* {@link DistributionSet}
|
||||
*/
|
||||
@EntityGraph(value = "SoftwareModule.artifacts", type = EntityGraphType.LOAD)
|
||||
List<SoftwareModule> findByAssignedTo(DistributionSet set);
|
||||
|
||||
/**
|
||||
* @param pageable
|
||||
* the page request to page the result set
|
||||
* @param set
|
||||
* to search for
|
||||
* @param type
|
||||
* to filter
|
||||
* @return all {@link SoftwareModule}s that are assigned to given
|
||||
* {@link DistributionSet} filtered by {@link SoftwareModuleType}.
|
||||
*/
|
||||
Page<SoftwareModule> findByAssignedToAndType(Pageable pageable, DistributionSet set, SoftwareModuleType type);
|
||||
|
||||
/**
|
||||
* retrieves all software modules with a given {@link SoftwareModuleType}
|
||||
* and {@link SoftwareModule#getId()}.
|
||||
*
|
||||
* @param ids
|
||||
* to search for
|
||||
* @param type
|
||||
* to search for
|
||||
* @return {@link List} of found {@link SoftwareModule}s
|
||||
*/
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("SELECT sm FROM SoftwareModule sm WHERE sm.id IN ?1 and sm.type = ?2")
|
||||
List<SoftwareModule> findByIdInAndType(Iterable<Long> ids, SoftwareModuleType type);
|
||||
|
||||
@Override
|
||||
<S extends SoftwareModule> List<S> save(Iterable<S> entities);
|
||||
|
||||
/**
|
||||
* retrieves all software modules with a given
|
||||
* {@link SoftwareModule#getId()}.
|
||||
*
|
||||
* @param ids
|
||||
* to search for
|
||||
* @return {@link List} of found {@link SoftwareModule}s
|
||||
*/
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("SELECT sm FROM SoftwareModule sm WHERE sm.id IN ?1")
|
||||
List<SoftwareModule> findByIdIn(Iterable<Long> ids);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Repository for {@link SoftwareModuleType}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface SoftwareModuleTypeRepository
|
||||
extends BaseEntityRepository<SoftwareModuleType, Long>, JpaSpecificationExecutor<SoftwareModuleType> {
|
||||
|
||||
/**
|
||||
* @param pageable
|
||||
* @param isDeleted
|
||||
* to <code>true</code> if only marked as deleted have to be
|
||||
* count or all undeleted.
|
||||
* @return found {@link SoftwareModuleType}s.
|
||||
*/
|
||||
Page<SoftwareModuleType> findByDeleted(Pageable pageable, boolean isDeleted);
|
||||
|
||||
/**
|
||||
* @param isDeleted
|
||||
* to <code>true</code> if only marked as deleted have to be
|
||||
* count or all undeleted.
|
||||
* @return number of {@link SoftwareModuleType}s in the repository.
|
||||
*/
|
||||
Long countByDeleted(boolean isDeleted);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* to search for
|
||||
* @return all {@link SoftwareModuleType}s in the repository with given
|
||||
* {@link SoftwareModuleType#getKey()}
|
||||
*/
|
||||
SoftwareModuleType findByKey(String key);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* to search for
|
||||
* @return all {@link SoftwareModuleType}s in the repository with given
|
||||
* {@link SoftwareModuleType#getName()}
|
||||
*/
|
||||
SoftwareModuleType findByName(String name);
|
||||
}
|
||||
@@ -0,0 +1,408 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.cache.TenancyCacheManager;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||
import org.eclipse.hawkbit.repository.model.TenantMetaData;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware.TenantRunner;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.cache.interceptor.SimpleKeyGenerator;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.support.ConfigurableConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* Central system management operations of the SP server.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
public class SystemManagement implements EnvironmentAware {
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
private TargetRepository targetRepository;
|
||||
|
||||
@Autowired
|
||||
private ActionRepository actionRepository;
|
||||
|
||||
@Autowired
|
||||
private DistributionSetRepository distributionSetRepository;
|
||||
|
||||
@Autowired
|
||||
private SoftwareModuleRepository softwareModuleRepository;
|
||||
|
||||
@Autowired
|
||||
private TenantMetaDataRepository tenantMetaDataRepository;
|
||||
|
||||
@Autowired
|
||||
private DistributionSetTypeRepository distributionSetTypeRepository;
|
||||
|
||||
@Autowired
|
||||
private SoftwareModuleTypeRepository softwareModuleTypeRepository;
|
||||
|
||||
@Autowired
|
||||
private TargetTagRepository targetTagRepository;
|
||||
|
||||
@Autowired
|
||||
private DistributionSetTagRepository distributionSetTagRepository;
|
||||
|
||||
@Autowired
|
||||
private ExternalArtifactRepository externalArtifactRepository;
|
||||
|
||||
@Autowired
|
||||
private LocalArtifactRepository artifactRepository;
|
||||
|
||||
@Autowired
|
||||
private ExternalArtifactProviderRepository externalArtifactProviderRepository;
|
||||
|
||||
@Autowired
|
||||
private TenantConfigurationRepository tenantConfigurationRepository;
|
||||
|
||||
@Autowired
|
||||
private TenantAware tenantAware;
|
||||
|
||||
@Autowired
|
||||
private TenancyCacheManager cacheManager;
|
||||
|
||||
private final ThreadLocal<String> createInitialTenant = new ThreadLocal<>();
|
||||
|
||||
private final ConfigurableConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
private Environment environment;
|
||||
|
||||
/**
|
||||
* Registers the key generator for the {@link #currentTenant()} method
|
||||
* because this key generator is aware of the {@link #createInitialTenant}
|
||||
* thread local in case we are currently creating a tenant and insert the
|
||||
* default distribution set types.
|
||||
*
|
||||
* @return the {@link CurrentTenantKeyGenerator}
|
||||
*/
|
||||
@Bean
|
||||
public CurrentTenantKeyGenerator currentTenantKeyGenerator() {
|
||||
return new CurrentTenantKeyGenerator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link TenantMetaData} of given and current tenant.
|
||||
*
|
||||
* DISCLAIMER: this variant is used during initial login (where the tenant
|
||||
* is not yet in teh session). Please user {@link #getTenantMetadata()} for
|
||||
* reluar requests.
|
||||
*
|
||||
* @param tenant
|
||||
* @return
|
||||
*/
|
||||
@Cacheable(value = "tenantMetadata", key = "#tenant.toUpperCase()")
|
||||
@Transactional
|
||||
@Modifying
|
||||
@NotNull
|
||||
public TenantMetaData getTenantMetadata(@NotNull final String tenant) {
|
||||
final TenantMetaData result = tenantMetaDataRepository.findByTenantIgnoreCase(tenant);
|
||||
|
||||
// Create if it does not exist
|
||||
if (result == null) {
|
||||
try {
|
||||
createInitialTenant.set(tenant);
|
||||
cacheManager.getCache("currentTenant").evict(currentTenantKeyGenerator().generate(null, null));
|
||||
return tenantMetaDataRepository.save(new TenantMetaData(createStandardSoftwareDataSetup(), tenant));
|
||||
} finally {
|
||||
createInitialTenant.remove();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return list of all tenant names in the system.
|
||||
*/
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
|
||||
// tenant independent
|
||||
public List<String> findTenants() {
|
||||
return tenantMetaDataRepository.findAll().stream().map(md -> md.getTenant()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all data related to a given tenant.
|
||||
*
|
||||
* @param tenant
|
||||
* to delete
|
||||
*/
|
||||
@CacheEvict(value = { "tenantMetadata" }, key = "#tenant.toUpperCase()")
|
||||
@Transactional
|
||||
@Modifying
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
|
||||
// tenant independent
|
||||
public void deleteTenant(@NotNull final String tenant) {
|
||||
cacheManager.evictCaches(tenant);
|
||||
cacheManager.getCache("currentTenant").evict(currentTenantKeyGenerator().generate(null, null));
|
||||
tenantAware.runAsTenant(tenant, new TenantRunner<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
entityManager.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, tenant.toUpperCase());
|
||||
tenantMetaDataRepository.deleteByTenantIgnoreCase(tenant);
|
||||
tenantConfigurationRepository.deleteByTenantIgnoreCase(tenant);
|
||||
targetRepository.deleteByTenantIgnoreCase(tenant);
|
||||
artifactRepository.deleteByTenantIgnoreCase(tenant);
|
||||
externalArtifactRepository.deleteByTenantIgnoreCase(tenant);
|
||||
externalArtifactProviderRepository.deleteByTenantIgnoreCase(tenant);
|
||||
targetTagRepository.deleteByTenantIgnoreCase(tenant);
|
||||
actionRepository.deleteByTenantIgnoreCase(tenant);
|
||||
distributionSetTagRepository.deleteByTenantIgnoreCase(tenant);
|
||||
distributionSetRepository.deleteByTenantIgnoreCase(tenant);
|
||||
distributionSetTypeRepository.deleteByTenantIgnoreCase(tenant);
|
||||
softwareModuleRepository.deleteByTenantIgnoreCase(tenant);
|
||||
softwareModuleTypeRepository.deleteByTenantIgnoreCase(tenant);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link TenantMetaData} of {@link TenantAware#getCurrentTenant()}
|
||||
*/
|
||||
@Cacheable(value = "tenantMetadata", keyGenerator = "tenantKeyGenerator")
|
||||
@Transactional
|
||||
@Modifying
|
||||
@NotNull
|
||||
public TenantMetaData getTenantMetadata() {
|
||||
if (tenantAware.getCurrentTenant() == null) {
|
||||
throw new IllegalStateException("Tenant not set");
|
||||
}
|
||||
|
||||
return getTenantMetadata(tenantAware.getCurrentTenant());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a specific tenant exists. The tenant will not be created lazy.
|
||||
*
|
||||
* @param tenant
|
||||
* the tenant to check
|
||||
* @return {@code true} in case the tenant exits or {@code false} if not
|
||||
*/
|
||||
@Cacheable(value = "currentTenant", keyGenerator = "currentTenantKeyGenerator")
|
||||
// MECS-903 set transaction to not supported, due we call this in
|
||||
// BaseEntity#prePersist methods
|
||||
// and it seems that JPA committing the transaction when executing this
|
||||
// transactional method,
|
||||
// which then leads that the BaseEntity#prePersist is called again to
|
||||
// persist the un-persisted
|
||||
// entity and we landing again in the #currentTenant() method
|
||||
// suspend the transaction here to do a read-request against the medata
|
||||
// table, when the current
|
||||
// tenant is not cached anyway already.
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
public String currentTenant() {
|
||||
final String initialTenantCreation = createInitialTenant.get();
|
||||
if (initialTenantCreation == null) {
|
||||
final TenantMetaData findByTenant = tenantMetaDataRepository
|
||||
.findByTenantIgnoreCase(tenantAware.getCurrentTenant());
|
||||
return findByTenant != null ? findByTenant.getTenant() : null;
|
||||
}
|
||||
return initialTenantCreation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update call for {@link TenantMetaData}.
|
||||
*
|
||||
* @param metaData
|
||||
* to update
|
||||
* @return updated {@link TenantMetaData} entity
|
||||
*/
|
||||
@CachePut(value = "tenantMetadata", key = "#metaData.tenant.toUpperCase()")
|
||||
@Transactional
|
||||
@Modifying
|
||||
@NotNull
|
||||
public TenantMetaData updateTenantMetadata(@NotNull final TenantMetaData metaData) {
|
||||
if (!tenantMetaDataRepository.exists(metaData.getId())) {
|
||||
throw new EntityNotFoundException("Metadata does not exist: " + metaData.getId());
|
||||
}
|
||||
|
||||
return tenantMetaDataRepository.save(metaData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a configuration value from the e.g. tenant overwritten
|
||||
* configuration values or in case the tenant does not a have a specific
|
||||
* configuration the global default value hold in the {@link Environment}.
|
||||
*
|
||||
* @param configurationKey
|
||||
* the key of the configuration
|
||||
* @param propertyType
|
||||
* the type of the configuration value, e.g. {@code String.class}
|
||||
* , {@code Integer.class}, etc
|
||||
* @return the converted configuration value either from the tenant specific
|
||||
* configuration stored or from the fallback default values or
|
||||
* {@code null} in case key has not been configured and not default
|
||||
* value exists
|
||||
* @throws ConversionFailedException
|
||||
* if the property cannot be converted to the given
|
||||
* {@code propertyType}
|
||||
*/
|
||||
@Cacheable(value = "tenantConfiguration", key = "#configurationKey.getKeyName()")
|
||||
public <T> T getConfigurationValue(final TenantConfigurationKey configurationKey, final Class<T> propertyType) {
|
||||
final TenantConfiguration tenantConfiguration = tenantConfigurationRepository
|
||||
.findByKey(configurationKey.getKeyName());
|
||||
if (tenantConfiguration != null) {
|
||||
return conversionService.convert(tenantConfiguration.getValue(), propertyType);
|
||||
} else if (configurationKey.getDefaultKeyName() != null) {
|
||||
final T defaultKeyNameValue = environment.getProperty(configurationKey.getDefaultKeyName(), propertyType);
|
||||
return defaultKeyNameValue != null ? defaultKeyNameValue
|
||||
: conversionService.convert(configurationKey.getDefaultValue(), propertyType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or updates a specific configuration for a specific tenant.
|
||||
*
|
||||
* @param tenantConf
|
||||
* the tenant configuration object which contains the key and
|
||||
* value of the specific configuration to update
|
||||
* @return the added or updated TenantConfiguration
|
||||
*/
|
||||
@CacheEvict(value = "tenantConfiguration", key = "#tenantConf.getKey()")
|
||||
@Transactional
|
||||
@Modifying
|
||||
public TenantConfiguration addOrUpdateConfiguration(final TenantConfiguration tenantConf) {
|
||||
TenantConfiguration tenantConfiguration = tenantConfigurationRepository.findByKey(tenantConf.getKey());
|
||||
if (tenantConfiguration != null) {
|
||||
tenantConfiguration.setValue(tenantConf.getValue());
|
||||
} else {
|
||||
tenantConfiguration = new TenantConfiguration(tenantConf.getKey(), tenantConf.getValue());
|
||||
}
|
||||
return tenantConfigurationRepository.save(tenantConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a specific configuration for the current tenant.
|
||||
*
|
||||
* @param configurationKey
|
||||
* the configuration key to be deleted
|
||||
*/
|
||||
@CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()")
|
||||
@Transactional
|
||||
@Modifying
|
||||
public void deleteConfiguration(final TenantConfigurationKey configurationKey) {
|
||||
tenantConfigurationRepository.deleteByKey(configurationKey.getKeyName());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<TenantConfiguration> getTenantConfigurations() {
|
||||
return tenantConfigurationRepository.findAll();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.context.EnvironmentAware#setEnvironment(org.
|
||||
* springframework.core.env. Environment)
|
||||
*/
|
||||
@Override
|
||||
public void setEnvironment(final Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
private DistributionSetType createStandardSoftwareDataSetup() {
|
||||
|
||||
// Edge Controller Linux standard setup
|
||||
final SoftwareModuleType eclApp = softwareModuleTypeRepository.save(new SoftwareModuleType("application",
|
||||
"ECL Application", "Edge Controller Linux base application type", 1));
|
||||
final SoftwareModuleType eclOs = softwareModuleTypeRepository
|
||||
.save(new SoftwareModuleType("os", "ECL OS", "Edge Controller Linux operation system image type", 1));
|
||||
final SoftwareModuleType eclJvm = softwareModuleTypeRepository.save(
|
||||
new SoftwareModuleType("runtime", "ECL JVM", "Edge Controller Linux java virtual machine type.", 1));
|
||||
|
||||
distributionSetTypeRepository.save(
|
||||
new DistributionSetType("ecl_os", "OS only", "Standard Edge Controller Linux distribution set type.")
|
||||
.addMandatoryModuleType(eclOs));
|
||||
|
||||
distributionSetTypeRepository.save(new DistributionSetType("ecl_os_app", "OS with optional app",
|
||||
"Standard Edge Controller Linux distribution set type. OS only.").addMandatoryModuleType(eclOs)
|
||||
.addOptionalModuleType(eclApp));
|
||||
|
||||
final DistributionSetType defaultType = distributionSetTypeRepository
|
||||
.save(new DistributionSetType("ecl_os_app_jvm", "OS with optional app and jvm",
|
||||
"Standard Edge Controller Linux distribution set type. OS with optional application.")
|
||||
.addMandatoryModuleType(eclOs).addOptionalModuleType(eclApp)
|
||||
.addOptionalModuleType(eclJvm));
|
||||
|
||||
return defaultType;
|
||||
}
|
||||
|
||||
/**
|
||||
* A implementation of the {@link KeyGenerator} to generate a key based on
|
||||
* either the {@code createInitialTenant} thread local and the
|
||||
* {@link TenantAware}, but in case we are in a tenant creation with its
|
||||
* default types we need to use the tenant the current tenant which is
|
||||
* currently created and not the one currently in the {@link TenantAware}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
private class CurrentTenantKeyGenerator implements KeyGenerator {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.cache.interceptor.KeyGenerator#generate(java.lang
|
||||
* .Object, java.lang.reflect.Method, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public Object generate(final Object target, final Method method, final Object... params) {
|
||||
final String initialTenantCreation = createInitialTenant.get();
|
||||
if (initialTenantCreation == null) {
|
||||
return SimpleKeyGenerator.generateKey(tenantAware.getCurrentTenant().toUpperCase(),
|
||||
tenantAware.getCurrentTenant().toUpperCase());
|
||||
}
|
||||
return SimpleKeyGenerator.generateKey(initialTenantCreation.toUpperCase(),
|
||||
initialTenantCreation.toUpperCase());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
*
|
||||
* Mangement service class for {@link Tag}s.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
public class TagManagement {
|
||||
|
||||
@Autowired
|
||||
private TargetTagRepository targetTagRepository;
|
||||
|
||||
@Autowired
|
||||
private TargetRepository targetRepository;
|
||||
|
||||
@Autowired
|
||||
private DistributionSetTagRepository distributionSetTagRepository;
|
||||
|
||||
@Autowired
|
||||
private DistributionSetRepository distributionSetRepository;
|
||||
|
||||
/**
|
||||
* Find {@link TargetTag} based on given Name.
|
||||
*
|
||||
* @param name
|
||||
* to look for.
|
||||
* @return {@link TargetTag} or <code>null</code> if it does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public TargetTag findTargetTag(@NotEmpty final String name) {
|
||||
return targetTagRepository.findByNameEquals(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TargetTag}.
|
||||
*
|
||||
* @param targetTag
|
||||
* to be created
|
||||
*
|
||||
* @return the new created {@link TargetTag}
|
||||
*
|
||||
* @throws EntityAlreadyExistsException
|
||||
* if given object already exists
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET)
|
||||
public TargetTag createTargetTag(@NotNull final TargetTag targetTag) {
|
||||
if (null != targetTag.getId()) {
|
||||
throw new EntityAlreadyExistsException();
|
||||
}
|
||||
|
||||
if (findTargetTag(targetTag.getName()) != null) {
|
||||
throw new EntityAlreadyExistsException();
|
||||
}
|
||||
|
||||
return targetTagRepository.save(targetTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* created multiple {@link TargetTag}s.
|
||||
*
|
||||
* @param targetTags
|
||||
* to be created
|
||||
* @return the new created {@link TargetTag}s
|
||||
*
|
||||
* @throws EntityAlreadyExistsException
|
||||
* if given object has already an ID.
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET)
|
||||
public List<TargetTag> createTargetTags(@NotNull final Iterable<TargetTag> targetTags) {
|
||||
targetTags.forEach(tag -> {
|
||||
if (tag.getId() != null) {
|
||||
throw new EntityAlreadyExistsException();
|
||||
}
|
||||
});
|
||||
|
||||
return targetTagRepository.save(targetTags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes {@link TargetTag} with given name.
|
||||
*
|
||||
* @param targetTagName
|
||||
* tag name of the {@link TargetTag} to be deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET)
|
||||
public void deleteTargetTag(@NotEmpty final String targetTagName) {
|
||||
final TargetTag tag = targetTagRepository.findByNameEquals(targetTagName);
|
||||
|
||||
final List<Target> changed = new LinkedList<Target>();
|
||||
for (final Target target : targetRepository.findByTag(tag)) {
|
||||
target.getTags().remove(tag);
|
||||
changed.add(target);
|
||||
}
|
||||
|
||||
// save association delete
|
||||
targetRepository.save(changed);
|
||||
|
||||
// finally delete the tag itself
|
||||
targetTagRepository.deleteByName(targetTagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all {@link TargetTag}s.
|
||||
*
|
||||
* @return all {@link TargetTag}s
|
||||
*/
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public List<TargetTag> findAllTargetTags() {
|
||||
return targetTagRepository.findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the {@link TargetTag}.
|
||||
*
|
||||
* @param targetTag
|
||||
* the {@link TargetTag}
|
||||
* @return the new {@link TargetTag}
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
public TargetTag updateTargetTag(@NotNull final TargetTag targetTag) {
|
||||
checkNotNull(targetTag.getName());
|
||||
checkNotNull(targetTag.getId());
|
||||
return targetTagRepository.save(targetTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find {@link DistributionSet} based on given name.
|
||||
*
|
||||
* @param name
|
||||
* to look for.
|
||||
* @return {@link DistributionSet} or <code>null</code> if it does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public DistributionSetTag findDistributionSetTag(@NotEmpty final String name) {
|
||||
return distributionSetTagRepository.findByNameEquals(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link DistributionSet}.
|
||||
*
|
||||
* @param distributionSetTag
|
||||
* to be created.
|
||||
* @return the new {@link DistributionSet}
|
||||
* @throws EntityAlreadyExistsException
|
||||
* if distributionSetTag already exists
|
||||
*
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
public DistributionSetTag createDistributionSetTag(@NotNull final DistributionSetTag distributionSetTag) {
|
||||
if (null != distributionSetTag.getId()) {
|
||||
throw new EntityAlreadyExistsException();
|
||||
}
|
||||
|
||||
if (distributionSetTagRepository.findByNameEquals(distributionSetTag.getName()) != null) {
|
||||
throw new EntityAlreadyExistsException();
|
||||
}
|
||||
|
||||
return distributionSetTagRepository.save(distributionSetTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates multiple {@link DistributionSetTag}s.
|
||||
*
|
||||
* @param distributionSetTags
|
||||
* to be created
|
||||
* @return the new {@link DistributionSetTag}
|
||||
* @throws EntityAlreadyExistsException
|
||||
* if a given entity already exists
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
public Iterable<DistributionSetTag> createDistributionSetTags(
|
||||
@NotNull final Iterable<DistributionSetTag> distributionSetTags) {
|
||||
for (final DistributionSetTag dsTag : distributionSetTags) {
|
||||
if (dsTag.getId() != null) {
|
||||
throw new EntityAlreadyExistsException();
|
||||
}
|
||||
}
|
||||
|
||||
return distributionSetTagRepository.save(distributionSetTags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes {@link DistributionSetTag} by given
|
||||
* {@link DistributionSetTag#getName()}.
|
||||
*
|
||||
* @param tagNames
|
||||
* to be deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
||||
public void deleteDistributionSetTag(@NotEmpty final String tagName) {
|
||||
final DistributionSetTag tag = distributionSetTagRepository.findByNameEquals(tagName);
|
||||
|
||||
final List<DistributionSet> changed = new LinkedList<DistributionSet>();
|
||||
for (final DistributionSet set : distributionSetRepository.findByTag(tag)) {
|
||||
set.getTags().remove(tag);
|
||||
changed.add(set);
|
||||
}
|
||||
|
||||
// save association delete
|
||||
distributionSetRepository.save(changed);
|
||||
|
||||
distributionSetTagRepository.deleteByName(tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing {@link DistributionSetTag}.
|
||||
*
|
||||
* @param distributionSetTag
|
||||
* to be updated
|
||||
* @return the updated {@link DistributionSet}
|
||||
* @throws NullPointerException
|
||||
* of {@link DistributionSetTag#getName()} is <code>null</code>
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
public DistributionSetTag updateDistributionSetTag(@NotNull final DistributionSetTag distributionSetTag) {
|
||||
checkNotNull(distributionSetTag.getName());
|
||||
checkNotNull(distributionSetTag.getId());
|
||||
return distributionSetTagRepository.save(distributionSetTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all {@link DistributionTag}s.
|
||||
*
|
||||
* @return all {@link DistributionTag}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public List<DistributionSetTag> findDistributionSetTagsAll() {
|
||||
return distributionSetTagRepository.findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds {@link TargetTag} by given id.
|
||||
*
|
||||
* @param id
|
||||
* to search for
|
||||
* @return the found {@link TargetTag}s or <code>null</code> if not found.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public TargetTag findTargetTagById(@NotNull final Long id) {
|
||||
return targetTagRepository.findOne(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds {@link DistributionSetTag} by given id.
|
||||
*
|
||||
* @param id
|
||||
* to search for
|
||||
* @return the found {@link DistributionSetTag}s or <code>null</code> if not
|
||||
* found.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public DistributionSetTag findDistributionSetTagById(@NotNull final Long id) {
|
||||
return distributionSetTagRepository.findOne(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all {@link TargetTag}s.
|
||||
*
|
||||
* @param pageReq
|
||||
* page parameter
|
||||
*
|
||||
* @return all {@link TargetTag}s
|
||||
*/
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Page<TargetTag> findAllTargetTags(@NotNull final Pageable pageReq) {
|
||||
return targetTagRepository.findAll(pageReq);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all {@link TargetTag}s.
|
||||
*
|
||||
* @param pageReq
|
||||
* page parameter
|
||||
* @return all {@link TargetTag}s
|
||||
*/
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public Page<DistributionSetTag> findDistributionSetTagsAll(@NotNull final Pageable pageReq) {
|
||||
return distributionSetTagRepository.findAll(pageReq);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.specifications.TargetFilterQuerySpecification;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.domain.Specifications;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
/**
|
||||
* Business service facade for managing {@link TargetFilterQuery}s.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
public class TargetFilterQueryManagement {
|
||||
|
||||
@Autowired
|
||||
private TargetFilterQueryRepository targetFilterQueryRepository;
|
||||
|
||||
/**
|
||||
* creating new {@link TargetFilterQuery}.
|
||||
*
|
||||
* @param customTargetFilter
|
||||
* @return the created {@link TargetFilterQuery}
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET)
|
||||
public TargetFilterQuery createTargetFilterQuery(@NotNull final TargetFilterQuery customTargetFilter) {
|
||||
|
||||
if (targetFilterQueryRepository.findByName(customTargetFilter.getName()) != null) {
|
||||
throw new EntityAlreadyExistsException(customTargetFilter.getName());
|
||||
}
|
||||
final TargetFilterQuery filter = targetFilterQueryRepository.save(customTargetFilter);
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete target filter query.
|
||||
*
|
||||
* @param targetFilterQueryId
|
||||
* IDs of target filter query to be deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET)
|
||||
public void deleteTargetFilterQuery(@NotNull final Long targetFilterQueryId) {
|
||||
targetFilterQueryRepository.delete(targetFilterQueryId);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Retrieves all target filter query{@link TargetFilterQuery}.
|
||||
*
|
||||
* @param pageable
|
||||
* pagination parameter
|
||||
* @return the found {@link TargetFilterQuery}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Page<TargetFilterQuery> findAllTargetFilterQuery(@NotNull final Pageable pageable) {
|
||||
return targetFilterQueryRepository.findAll(pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all target filter query which {@link TargetFilterQuery}.
|
||||
*
|
||||
*
|
||||
* @param pageable
|
||||
* pagination parameter
|
||||
* @param name
|
||||
* target filter query name
|
||||
* @return the page with the found {@link TargetFilterQuery}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public Page<TargetFilterQuery> findTargetFilterQueryByFilters(@NotNull final Pageable pageable, final String name) {
|
||||
final List<Specification<TargetFilterQuery>> specList = new ArrayList<Specification<TargetFilterQuery>>();
|
||||
if (!Strings.isNullOrEmpty(name)) {
|
||||
specList.add(TargetFilterQuerySpecification.likeName(name));
|
||||
}
|
||||
return findTargetFilterQueryByCriteriaAPI(pageable, specList);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pageable
|
||||
* pagination parameter
|
||||
* @param specList
|
||||
* list of @link {@link Specification}
|
||||
* @return the page with the found {@link TargetFilterQuery}
|
||||
*/
|
||||
private Page<TargetFilterQuery> findTargetFilterQueryByCriteriaAPI(@NotNull final Pageable pageable,
|
||||
final List<Specification<TargetFilterQuery>> specList) {
|
||||
Specifications<TargetFilterQuery> specs = null;
|
||||
if (!specList.isEmpty()) {
|
||||
specs = Specifications.where(specList.get(0));
|
||||
}
|
||||
if (specList.size() > 1) {
|
||||
for (final Specification<TargetFilterQuery> s : specList.subList(1, specList.size())) {
|
||||
specs = specs.and(s);
|
||||
}
|
||||
}
|
||||
if (specs == null) {
|
||||
return targetFilterQueryRepository.findAll(pageable);
|
||||
} else {
|
||||
return targetFilterQueryRepository.findAll(specs, pageable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find target filter query by name.
|
||||
*
|
||||
* @param targetFilterQueryName
|
||||
* Target filter query name
|
||||
* @return the found {@link TargetFilterQuery}
|
||||
*
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public TargetFilterQuery findTargetFilterQueryByName(@NotNull final String targetFilterQueryName) {
|
||||
return targetFilterQueryRepository.findByName(targetFilterQueryName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find target filter query by id.
|
||||
*
|
||||
* @param targetFilterQueryId
|
||||
* Target filter query id
|
||||
* @return the found {@link TargetFilterQuery}
|
||||
*
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
public TargetFilterQuery findTargetFilterQueryById(@NotNull final Long targetFilterQueryId) {
|
||||
return targetFilterQueryRepository.findOne(targetFilterQueryId);
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the {@link TargetFilterQuery}.
|
||||
*
|
||||
* @param targetFilterQuery
|
||||
* to be updated
|
||||
* @return the updated {@link TargetFilterQuery}
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
public TargetFilterQuery updateTargetFilterQuery(@NotNull final TargetFilterQuery targetFilterQuery) {
|
||||
Assert.notNull(targetFilterQuery.getId());
|
||||
return targetFilterQueryRepository.save(targetFilterQuery);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TargetFilterQueryRepository extends
|
||||
BaseEntityRepository<TargetFilterQuery, Long>,
|
||||
JpaSpecificationExecutor<TargetFilterQuery> {
|
||||
|
||||
/**
|
||||
* Find customer target filter by name
|
||||
*
|
||||
* @param name
|
||||
* @return custom target filter
|
||||
*/
|
||||
TargetFilterQuery findByName(final String name);
|
||||
|
||||
/**
|
||||
* Find list of all custom target filters.
|
||||
*/
|
||||
@Override
|
||||
Page<TargetFilterQuery> findAll();
|
||||
|
||||
@Override
|
||||
@Modifying
|
||||
@Transactional
|
||||
<S extends TargetFilterQuery> S save(S entity);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
/**
|
||||
* Usually a JPA spring data repository to handle {@link TargetInfo} entity.
|
||||
* However, do to an eclipselink bug with spring boot now a regular interface
|
||||
* that is implemented by {@link EclipseLinkTargetInfoRepository}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface TargetInfoRepository {
|
||||
|
||||
/**
|
||||
* Sets new TargetUpdateStatus of given target if is not already on that
|
||||
* value.
|
||||
*
|
||||
* @param status
|
||||
* to set
|
||||
* @param targets
|
||||
* to set it for
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("update TargetInfo ti set ti.updateStatus = :status where ti.targetId in :targets and ti.updateStatus != :status")
|
||||
void setTargetUpdateStatus(@Param("status") TargetUpdateStatus status, @Param("targets") List<Long> targets);
|
||||
|
||||
/**
|
||||
* Save entity and evict cache with it.
|
||||
*
|
||||
* @param entity
|
||||
* to persists
|
||||
*
|
||||
* @return persisted or updated {@link Entity}
|
||||
*/
|
||||
@CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true)
|
||||
<S extends TargetInfo> S save(S entity);
|
||||
|
||||
/**
|
||||
* Deletes info entries by ID.
|
||||
*
|
||||
* @param targetIDs
|
||||
* to delete
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true)
|
||||
void deleteByTargetIdIn(final Collection<Long> targetIDs);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link Target} repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TargetRepository extends BaseEntityRepository<Target, Long>, JpaSpecificationExecutor<Target> {
|
||||
|
||||
/**
|
||||
* Loads {@link Target} including details {@link EntityGraph} by given ID.
|
||||
*
|
||||
* @param controllerID
|
||||
* to search for
|
||||
* @return found {@link Target} or <code>null</code> if not found.
|
||||
*/
|
||||
@EntityGraph(value = "Target.detail", type = EntityGraphType.LOAD)
|
||||
Target findByControllerId(String controllerID);
|
||||
|
||||
/**
|
||||
* Finds targets by given list of {@link Target#getControllerId()}s.
|
||||
*
|
||||
* @param controllerIDs
|
||||
* to serach for
|
||||
* @return list of found {@link Target}s
|
||||
*/
|
||||
List<Target> findByControllerIdIn(String... controllerIDs);
|
||||
|
||||
/**
|
||||
* Deletes the {@link Target}s with the given target IDs.
|
||||
*
|
||||
* @param targetIDs
|
||||
* to be deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("DELETE FROM Target t WHERE t.id IN ?1")
|
||||
void deleteByIdIn(final Collection<Long> targetIDs);
|
||||
|
||||
/**
|
||||
* Finds {@link Target}s by assigned {@link Tag}.
|
||||
*
|
||||
* @param tag
|
||||
* to be found
|
||||
* @return list of found targets
|
||||
*/
|
||||
@Query(value = "SELECT DISTINCT t FROM Target t JOIN t.tags tt WHERE tt = :tag")
|
||||
List<Target> findByTag(@Param("tag") final TargetTag tag);
|
||||
|
||||
/**
|
||||
* Finds all {@link Target}s based on given {@link Target#getControllerId()}
|
||||
* list and assigned {@link Tag#getName()}.
|
||||
*
|
||||
* @param tag
|
||||
* to search for
|
||||
* @param controllerIds
|
||||
* to search for
|
||||
* @return {@link List} of found {@link Target}s.
|
||||
*/
|
||||
@Query(value = "SELECT DISTINCT t from Target t JOIN t.tags tt WHERE tt.name = :tagname AND t.controllerId IN :targets")
|
||||
List<Target> findByTagNameAndControllerIdIn(@Param("tagname") final String tag,
|
||||
@Param("targets") final Collection<String> controllerIds);
|
||||
|
||||
/**
|
||||
* Used by UI to filter based on selected status.
|
||||
*
|
||||
* @param pageable
|
||||
* for page configuration
|
||||
* @param status
|
||||
* to filter for
|
||||
*
|
||||
* @return found targets
|
||||
*/
|
||||
Page<Target> findByTargetInfoUpdateStatus(final Pageable pageable, final TargetUpdateStatus status);
|
||||
|
||||
/**
|
||||
* Finds all targets that have defined {@link DistributionSet} installed.
|
||||
*
|
||||
* @param pageable
|
||||
* for page configuration
|
||||
* @param set
|
||||
* is the {@link DistributionSet} to filter for.
|
||||
*
|
||||
* @return found targets
|
||||
*/
|
||||
Page<Target> findByTargetInfoInstalledDistributionSet(final Pageable pageable, final DistributionSet set);
|
||||
|
||||
/**
|
||||
* retrieves the {@link Target}s which has the {@link DistributionSet}
|
||||
* installed with the given ID.
|
||||
*
|
||||
* @param pageable
|
||||
* parameter
|
||||
* @param setID
|
||||
* the ID of the {@link DistributionSet}
|
||||
* @return the found {@link Target}s
|
||||
*/
|
||||
Page<Target> findByTargetInfoInstalledDistributionSetId(final Pageable pageable, final Long setID);
|
||||
|
||||
/**
|
||||
* Finds all targets that have defined {@link DistributionSet} assigned.
|
||||
*
|
||||
* @param pageable
|
||||
* for page configuration
|
||||
* @param set
|
||||
* is the {@link DistributionSet} to filter for.
|
||||
*
|
||||
* @return found targets
|
||||
*/
|
||||
Page<Target> findByAssignedDistributionSet(final Pageable pageable, final DistributionSet set);
|
||||
|
||||
/**
|
||||
* Saves all given {@link Target}s.
|
||||
*
|
||||
* @param entities
|
||||
* @return the saved entities
|
||||
* @throws IllegalArgumentException
|
||||
* in case the given entity is (@literal null}.
|
||||
*
|
||||
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
|
||||
*/
|
||||
@Override
|
||||
@Modifying
|
||||
@Transactional
|
||||
@CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true)
|
||||
<S extends Target> List<S> save(Iterable<S> entities);
|
||||
|
||||
/**
|
||||
* Saves a given entity. Use the returned instance for further operations as
|
||||
* the save operation might have changed the entity instance completely.
|
||||
*
|
||||
* @param entity
|
||||
* the target to save
|
||||
* @return the saved entity
|
||||
*/
|
||||
@Override
|
||||
@Modifying
|
||||
@Transactional
|
||||
@CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true)
|
||||
<S extends Target> S save(S entity);
|
||||
|
||||
/**
|
||||
* Finds all targets that have defined {@link DistributionSet} assigned.
|
||||
*
|
||||
* @param pageable
|
||||
* for page configuration
|
||||
* @param setID
|
||||
* is the ID of the {@link DistributionSet} to filter for.
|
||||
*
|
||||
* @return page of found targets
|
||||
*/
|
||||
Page<Target> findByAssignedDistributionSetId(final Pageable pageable, final Long setID);
|
||||
|
||||
/**
|
||||
* Counts number of targets with given
|
||||
* {@link Target#getAssignedDistributionSet()}.
|
||||
*
|
||||
* @param distId
|
||||
* to search for
|
||||
*
|
||||
* @return number of found {@link Target}s.
|
||||
*/
|
||||
Long countByAssignedDistributionSetId(final Long distId);
|
||||
|
||||
/**
|
||||
* @param ids
|
||||
* of count in DB
|
||||
* @return number of found {@link Target}s with given
|
||||
* {@link Target#getControllerId()}s
|
||||
*/
|
||||
@Query("SELECT COUNT(t) FROM Target t WHERE t.controllerId IN ?1")
|
||||
Long countByControllerIdIn(final Collection<String> ids);
|
||||
|
||||
/**
|
||||
* Counts number of targets with given
|
||||
* {@link TargetStatus#getInstalledDistributionSet()}.
|
||||
*
|
||||
* @param distId
|
||||
* to search for
|
||||
* @return number of found {@link Target}s.
|
||||
*/
|
||||
Long countByTargetInfoInstalledDistributionSetId(final Long distId);
|
||||
|
||||
/**
|
||||
* Finds all targets that have defined {@link DistributionSet} assigned or
|
||||
* installed.
|
||||
*
|
||||
* @param pageable
|
||||
* for page configuration
|
||||
* @param assigned
|
||||
* {@link DistributionSet} filter for; please note: must not be
|
||||
* null
|
||||
* @param installed
|
||||
* {@link DistributionSet} filter for; please note: must not be
|
||||
* null
|
||||
*
|
||||
* @return found targets
|
||||
*/
|
||||
Page<Target> findByAssignedDistributionSetOrTargetInfoInstalledDistributionSet(final Pageable pageable,
|
||||
final DistributionSet assigned, final DistributionSet installed);
|
||||
|
||||
/**
|
||||
* Finds all targets that have defined {@link DistributionSet} assigned or
|
||||
* installed.
|
||||
*
|
||||
* @param pageable
|
||||
* for page configuration
|
||||
* @param assigned
|
||||
* {@link DistributionSet} filter for; please note: must not be
|
||||
* null
|
||||
* @param installed
|
||||
* {@link DistributionSet} filter for; please note: must not be
|
||||
* null
|
||||
* @return found targets
|
||||
*/
|
||||
Page<Target> findByAssignedDistributionSetIdOrTargetInfoInstalledDistributionSetId(final Pageable pageable,
|
||||
final Long assigned, final Long installed);
|
||||
|
||||
/**
|
||||
* Finds all {@link Target}s in the repository.
|
||||
*
|
||||
* @return {@link List} of {@link Target}s
|
||||
*
|
||||
* @see org.springframework.data.repository.CrudRepository#findAll()
|
||||
*/
|
||||
@Override
|
||||
List<Target> findAll();
|
||||
|
||||
@Override
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("SELECT t FROM Target t WHERE t.id IN ?1")
|
||||
List<Target> findAll(Iterable<Long> ids);
|
||||
|
||||
/**
|
||||
* Sets {@link Target#getAssignedDistributionSet()}.
|
||||
*
|
||||
* @param set
|
||||
* to use
|
||||
* @param modifiedAt
|
||||
* current time
|
||||
* @param modifiedBy
|
||||
* current auditor
|
||||
* @param targets
|
||||
* to update
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("UPDATE Target t SET t.assignedDistributionSet = :set, t.lastModifiedAt = :lastModifiedAt, t.lastModifiedBy = :lastModifiedBy WHERE t.id IN :targets")
|
||||
void setAssignedDistributionSet(@Param("set") DistributionSet set, @Param("lastModifiedAt") Long modifiedAt,
|
||||
@Param("lastModifiedBy") String modifiedBy, @Param("targets") Collection<Long> targets);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
|
||||
/**
|
||||
* Result object for {@link TargetTag} assigments.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class TargetTagAssigmentResult extends AssignmentResult {
|
||||
|
||||
private final int unassigned;
|
||||
private final List<Target> assignedTargets;
|
||||
private final List<Target> unassignedTargets;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param alreadyAssigned
|
||||
* number of already assigned/ignored elements
|
||||
* @param assigned
|
||||
* number of newly assigned elements
|
||||
* @param unassigned
|
||||
* number of newly assigned elements
|
||||
* @param assignedTargets
|
||||
* {@link List} of assigned {@link Target}s.
|
||||
* @param unassignedTargets
|
||||
* {@link List} of unassigned {@link Target}s.
|
||||
*/
|
||||
public TargetTagAssigmentResult(final int alreadyAssigned, final int assigned, final int unassigned,
|
||||
final List<Target> assignedTargets, final List<Target> unassignedTargets) {
|
||||
super(assigned, alreadyAssigned);
|
||||
this.unassigned = unassigned;
|
||||
this.assignedTargets = assignedTargets;
|
||||
this.unassignedTargets = unassignedTargets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the unassigned
|
||||
*/
|
||||
public int getUnassigned() {
|
||||
return unassigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the assignedTargets
|
||||
*/
|
||||
public List<Target> getAssignedTargets() {
|
||||
return assignedTargets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the unassignedTargets
|
||||
*/
|
||||
public List<Target> getUnassignedTargets() {
|
||||
return unassignedTargets;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link TargetTag} repository.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TargetTagRepository extends BaseEntityRepository<TargetTag, Long> {
|
||||
|
||||
/**
|
||||
* deletes the {@link TargetTag}s with the given tag names.
|
||||
*
|
||||
* @param tagNames
|
||||
* to be deleted
|
||||
* @return 1 if tag was deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
Long deleteByName(final String tagName);
|
||||
|
||||
/**
|
||||
* find {@link TargetTag} by its name.
|
||||
*
|
||||
* @param tagName
|
||||
* to filter on
|
||||
* @return the {@link TargetTag} if found, otherwise null
|
||||
*/
|
||||
TargetTag findByNameEquals(final String tagName);
|
||||
|
||||
/**
|
||||
* Returns all instances of the type.
|
||||
*
|
||||
* @return all entities
|
||||
*/
|
||||
@Override
|
||||
List<TargetTag> findAll();
|
||||
|
||||
@Override
|
||||
<S extends TargetTag> List<S> save(Iterable<S> entities);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
|
||||
/**
|
||||
* A custom JPA database return value object with the proper constructor so JPA
|
||||
* is able to parse the result-set directly into this object.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class TargetWithActionType {
|
||||
|
||||
private final String targetId;
|
||||
private final ActionType actionType;
|
||||
private final long forceTime;
|
||||
|
||||
/**
|
||||
* @param targetId
|
||||
* @param actionType
|
||||
* @param forceTime
|
||||
*/
|
||||
public TargetWithActionType(final String targetId, final ActionType actionType, final long forceTime) {
|
||||
this.targetId = targetId;
|
||||
this.actionType = actionType;
|
||||
this.forceTime = forceTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionType
|
||||
*/
|
||||
public ActionType getActionType() {
|
||||
if (actionType != null) {
|
||||
return actionType;
|
||||
}
|
||||
// default value
|
||||
return ActionType.FORCED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the forceTime
|
||||
*/
|
||||
public long getForceTime() {
|
||||
if (actionType == ActionType.TIMEFORCED) {
|
||||
return forceTime;
|
||||
}
|
||||
return Action.NO_FORCE_TIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the targetId
|
||||
*/
|
||||
public String getTargetId() {
|
||||
return targetId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* The spring-data repository for the entity {@link TenantConfiguration}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TenantConfigurationRepository extends BaseEntityRepository<TenantConfiguration, Long> {
|
||||
|
||||
/**
|
||||
* Finds a specific {@link TenantConfiguration} by the configuration key.
|
||||
*
|
||||
* @param configurationKey
|
||||
* the configuration key to find the configuration for
|
||||
* @return the found tenant configuration object otherwise {@code null}
|
||||
*/
|
||||
TenantConfiguration findByKey(String configurationKey);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.CrudRepository#findAll()
|
||||
*/
|
||||
@Override
|
||||
List<TenantConfiguration> findAll();
|
||||
|
||||
/**
|
||||
* Deletes a tenant configuration by tenant and key.
|
||||
*
|
||||
* @param tenant
|
||||
* the tenant for this configuration
|
||||
* @param keyName
|
||||
* the name of the key to be deleted
|
||||
*/
|
||||
void deleteByKey(String keyName);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* {@link KeyGenerator} for tenant related caches.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class TenantKeyGenerator implements KeyGenerator {
|
||||
|
||||
@Autowired
|
||||
private TenantAware tenantAware;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.cache.interceptor.KeyGenerator#generate(java.lang.
|
||||
* Object, java.lang.reflect.Method, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public Object generate(final Object target, final Method method, final Object... params) {
|
||||
return tenantAware.getCurrentTenant().toUpperCase();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.TenantMetaData;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* repository for operations on {@link TenantMetaData} entity.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TenantMetaDataRepository extends PagingAndSortingRepository<TenantMetaData, Long> {
|
||||
|
||||
/**
|
||||
* Search {@link TenantMetaData} by tenant name.
|
||||
*
|
||||
* @param tenant
|
||||
* to search for
|
||||
* @return found {@link TenantMetaData} or <code>null</code>
|
||||
*/
|
||||
TenantMetaData findByTenantIgnoreCase(String tenant);
|
||||
|
||||
/**
|
||||
* Counts the tenant by the tenant field which is either a count of one or a
|
||||
* count of zero, this is mostly to check if the tenant exists.
|
||||
*
|
||||
* @param tenant
|
||||
* the name of the tenant to check if it is exists
|
||||
* @return the count of the tenant by name which is either one or zero
|
||||
*/
|
||||
Long countByTenantIgnoreCase(String tenant);
|
||||
|
||||
@Override
|
||||
List<TenantMetaData> findAll();
|
||||
|
||||
/**
|
||||
* @param tenant
|
||||
*/
|
||||
void deleteByTenantIgnoreCase(String tenant);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 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.event;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent;
|
||||
import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent;
|
||||
import org.eclipse.hawkbit.eventbus.event.TargetInfoUpdateEvent;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
/**
|
||||
* Defines all events which are sent from the {@link DeploymentManagement}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class DeploymentManagementEvents {
|
||||
|
||||
@Autowired
|
||||
private EventBus eventBus;
|
||||
|
||||
/**
|
||||
* Sends the {@link TargetAssignDistributionSetEvent} for a specific target
|
||||
* to the {@link EventBus}.
|
||||
*
|
||||
* @param target
|
||||
* the Target which has been assigned to a distribution set
|
||||
* @param actionId
|
||||
* the action id of the assignment
|
||||
* @param softwareModules
|
||||
* the software modules which have been assigned
|
||||
*/
|
||||
public void assignDistributionSet(final Target target, final Long actionId,
|
||||
final List<SoftwareModule> softwareModules) {
|
||||
target.getTargetInfo().setUpdateStatus(TargetUpdateStatus.PENDING);
|
||||
eventBus.post(new TargetInfoUpdateEvent(target.getTargetInfo()));
|
||||
eventBus.post(new TargetAssignDistributionSetEvent(target.getControllerId(), actionId, softwareModules,
|
||||
target.getTargetInfo().getAddress()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the {@link CancelTargetAssignmentEvent} for a specific target to
|
||||
* the {@link EventBus}.
|
||||
*
|
||||
* @param target
|
||||
* the Target which has been assigned to a distribution set
|
||||
* @param actionId
|
||||
* the action id of the assignment
|
||||
*/
|
||||
public void cancalAssignDistributionSet(final Target target, final Long actionId) {
|
||||
eventBus.post(new CancelTargetAssignmentEvent(target.getControllerId(), actionId,
|
||||
target.getTargetInfo().getAddress()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* Thrown if artifact deletion failed.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class ArtifactDeleteFailedException extends SpServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new FileUploadFailedException with
|
||||
* {@link SpServerError#SP_REST_BODY_NOT_READABLE} error.
|
||||
*/
|
||||
public ArtifactDeleteFailedException() {
|
||||
super(SpServerError.SP_ARTIFACT_DELETE_FAILED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public ArtifactDeleteFailedException(final Throwable cause) {
|
||||
super(SpServerError.SP_ARTIFACT_DELETE_FAILED, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public ArtifactDeleteFailedException(final String message) {
|
||||
super(message, SpServerError.SP_ARTIFACT_DELETE_FAILED);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class ArtifactUploadFailedException extends SpServerRtException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new FileUploadFailedException with
|
||||
* {@link SpServerError#SP_REST_BODY_NOT_READABLE} error.
|
||||
*/
|
||||
public ArtifactUploadFailedException() {
|
||||
super(SpServerError.SP_ARTIFACT_UPLOAD_FAILED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public ArtifactUploadFailedException(final Throwable cause) {
|
||||
super(SpServerError.SP_ARTIFACT_UPLOAD_FAILED, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public ArtifactUploadFailedException(final String message) {
|
||||
super(message, SpServerError.SP_ARTIFACT_UPLOAD_FAILED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* for the error
|
||||
* @param cause
|
||||
* of the error
|
||||
*/
|
||||
public ArtifactUploadFailedException(final String message, final Throwable cause) {
|
||||
super(message, SpServerError.SP_ARTIFACT_UPLOAD_FAILED, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* Thrown if cancelation of actions is performened where the action is not
|
||||
* cancelable, e.g. the action is not active or is already a cancel action.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class CancelActionNotAllowedException extends SpServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new CancelActionNotAllowed with
|
||||
* {@link SpServerError#SP_ACTION_NOT_CANCELABLE} error.
|
||||
*/
|
||||
public CancelActionNotAllowedException() {
|
||||
super(SpServerError.SP_ACTION_NOT_CANCELABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public CancelActionNotAllowedException(final Throwable cause) {
|
||||
super(SpServerError.SP_ACTION_NOT_CANCELABLE, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public CancelActionNotAllowedException(final String message) {
|
||||
super(message, SpServerError.SP_ACTION_NOT_CANCELABLE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* {@link ConcurrentModificationException} is thrown when a given entity in's
|
||||
* actual and cannot be stored within the current session. Reason could be that
|
||||
* it has been changed within another session.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ConcurrentModificationException extends SpServerRtException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_CONCURRENT_MODIFICATION;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public ConcurrentModificationException() {
|
||||
super(THIS_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public ConcurrentModificationException(final Throwable cause) {
|
||||
super(THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* custom error message
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public ConcurrentModificationException(final String message, final Throwable cause) {
|
||||
super(message, THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* custom error message
|
||||
*/
|
||||
public ConcurrentModificationException(final String message) {
|
||||
super(message, THIS_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* Thrown if DS creation failed.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class DistributionSetCreationFailedMissingMandatoryModuleException extends SpServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new FileUploadFailedException with
|
||||
* {@link SpServerError#SP_DS_CREATION_FAILED_MISSING_MODULE} error.
|
||||
*/
|
||||
public DistributionSetCreationFailedMissingMandatoryModuleException() {
|
||||
super(SpServerError.SP_DS_CREATION_FAILED_MISSING_MODULE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public DistributionSetCreationFailedMissingMandatoryModuleException(final Throwable cause) {
|
||||
super(SpServerError.SP_DS_CREATION_FAILED_MISSING_MODULE, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public DistributionSetCreationFailedMissingMandatoryModuleException(final String message) {
|
||||
super(message, SpServerError.SP_DS_CREATION_FAILED_MISSING_MODULE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
|
||||
/**
|
||||
* Thrown if the user tries to assign modules to a {@link DistributionSet} that
|
||||
* has to {@link DistributionSetType} defined.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class DistributionSetTypeUndefinedException extends SpServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new FileUploadFailedException with
|
||||
* {@link SpServerError#SP_DS_TYPE_UNDEFINED} error.
|
||||
*/
|
||||
public DistributionSetTypeUndefinedException() {
|
||||
super(SpServerError.SP_DS_TYPE_UNDEFINED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public DistributionSetTypeUndefinedException(final Throwable cause) {
|
||||
super(SpServerError.SP_DS_TYPE_UNDEFINED, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public DistributionSetTypeUndefinedException(final String message) {
|
||||
super(message, SpServerError.SP_DS_TYPE_UNDEFINED);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* the {@link EntityAlreadyExistsException} is thrown when a entity is tried to
|
||||
* be saved which already exists or which violates unique key constraints.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class EntityAlreadyExistsException extends SpServerRtException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_ENTITY_ALRREADY_EXISTS;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public EntityAlreadyExistsException() {
|
||||
super(THIS_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public EntityAlreadyExistsException(final Throwable cause) {
|
||||
super(THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public EntityAlreadyExistsException(final String message, final Throwable cause) {
|
||||
super(message, THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
*/
|
||||
public EntityAlreadyExistsException(final String message) {
|
||||
super(message, THIS_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* The {@link EntityLockedException} is thrown when an entity has been locked by
|
||||
* the server to prevent modification.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class EntityLockedException extends SpServerRtException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final SpServerError THIS_ERROR = SpServerError.SP_ENTITY_LOCKED;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public EntityLockedException() {
|
||||
super(THIS_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public EntityLockedException(final Throwable cause) {
|
||||
super(THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public EntityLockedException(final String message, final Throwable cause) {
|
||||
super(message, THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
*/
|
||||
public EntityLockedException(final String message) {
|
||||
super(message, THIS_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* the {@link EntityNotFoundException} is thrown when a entity is tried find but
|
||||
* not found.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class EntityNotFoundException extends SpServerRtException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_ENTITY_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public EntityNotFoundException() {
|
||||
super(THIS_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public EntityNotFoundException(final Throwable cause) {
|
||||
super(THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public EntityNotFoundException(final String message, final Throwable cause) {
|
||||
super(message, THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
*/
|
||||
public EntityNotFoundException(final String message) {
|
||||
super(message, THIS_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_ENTITY_READ_ONLY;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public EntityReadOnlyException() {
|
||||
super(THIS_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public EntityReadOnlyException(final Throwable cause) {
|
||||
super(THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public EntityReadOnlyException(final String message, final Throwable cause) {
|
||||
super(message, THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
*/
|
||||
public EntityReadOnlyException(final String message) {
|
||||
super(message, THIS_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class GridFSDBFileNotFoundException extends SpServerRtException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new FileUploadFailedException with
|
||||
* {@link SpServerError#SP_REST_BODY_NOT_READABLE} error.
|
||||
*/
|
||||
public GridFSDBFileNotFoundException() {
|
||||
super(SpServerError.SP_ARTIFACT_LOAD_FAILED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public GridFSDBFileNotFoundException(final Throwable cause) {
|
||||
super(SpServerError.SP_ARTIFACT_LOAD_FAILED, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public GridFSDBFileNotFoundException(final String message) {
|
||||
super(message, SpServerError.SP_ARTIFACT_LOAD_FAILED);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* Thrown if a distribution set is assigned to a a target that is incomplete
|
||||
* (i.e. mandatory modules are missing).
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class IncompleteDistributionSetException extends SpServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new IncompleteDistributionSetException with
|
||||
* {@link SpServerError#SP_DS_INCOMPLETE} error.
|
||||
*/
|
||||
public IncompleteDistributionSetException() {
|
||||
super(SpServerError.SP_DS_INCOMPLETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public IncompleteDistributionSetException(final Throwable cause) {
|
||||
super(SpServerError.SP_DS_INCOMPLETE, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public IncompleteDistributionSetException(final String message) {
|
||||
super(message, SpServerError.SP_DS_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
@@ -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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* Exception which is thrown in case the current security context object does
|
||||
* not hold a required authority/permission.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class InsufficientPermissionException extends SpServerRtException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* creates new InsufficientPermissionException.
|
||||
*
|
||||
* @param cause
|
||||
* the cause of the exception
|
||||
*/
|
||||
public InsufficientPermissionException(final Throwable cause) {
|
||||
super(SpServerError.SP_INSUFFICIENT_PERMISSION, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates new InsufficientPermissionException.
|
||||
*/
|
||||
public InsufficientPermissionException() {
|
||||
this(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* Thrown if MD5 checksum check fails.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class InvalidMD5HashException extends SpServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new FileUploadFailedException with
|
||||
* {@link SpServerError#SP_ARTIFACT_UPLOAD_FAILED_MD5_MATCH} error.
|
||||
*/
|
||||
public InvalidMD5HashException() {
|
||||
super(SpServerError.SP_ARTIFACT_UPLOAD_FAILED_MD5_MATCH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public InvalidMD5HashException(final String message, final Throwable cause) {
|
||||
super(message, SpServerError.SP_ARTIFACT_UPLOAD_FAILED_MD5_MATCH, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public InvalidMD5HashException(final String message) {
|
||||
super(message, SpServerError.SP_ARTIFACT_UPLOAD_FAILED_MD5_MATCH);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* Thrown if SHA1 checksum check fails.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class InvalidSHA1HashException extends SpServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new FileUploadFailedException with
|
||||
* {@link SpServerError#SP_ARTIFACT_UPLOAD_FAILED_SHA1_MATCH} error.
|
||||
*/
|
||||
public InvalidSHA1HashException() {
|
||||
super(SpServerError.SP_ARTIFACT_UPLOAD_FAILED_SHA1_MATCH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public InvalidSHA1HashException(final String message, final Throwable cause) {
|
||||
super(message, SpServerError.SP_ARTIFACT_UPLOAD_FAILED_SHA1_MATCH, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public InvalidSHA1HashException(final String message) {
|
||||
super(message, SpServerError.SP_ARTIFACT_UPLOAD_FAILED_SHA1_MATCH);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* the {@link TenantNotExistException} is thrown when e.g. a controller tries to
|
||||
* register itself at SP as plug'n play target and the tenant specified in the
|
||||
* URL for this target does not exist. To avoid that targets could register
|
||||
* automatically new tenants.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class TenantNotExistException extends SpServerRtException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_TENANT_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public TenantNotExistException() {
|
||||
super(THIS_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public TenantNotExistException(final Throwable cause) {
|
||||
super(THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public TenantNotExistException(final String message, final Throwable cause) {
|
||||
super(message, THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
*/
|
||||
public TenantNotExistException(final String message) {
|
||||
super(message, THIS_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* Thrown if too many status entries have been inserted.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class ToManyAttributeEntriesException extends SpServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new FileUploadFailedException with
|
||||
* {@link SpServerError#SP_ATTRIBUTES_TO_MANY_ENTRIES} error.
|
||||
*/
|
||||
public ToManyAttributeEntriesException() {
|
||||
super(SpServerError.SP_ATTRIBUTES_TO_MANY_ENTRIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public ToManyAttributeEntriesException(final Throwable cause) {
|
||||
super(SpServerError.SP_ATTRIBUTES_TO_MANY_ENTRIES, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public ToManyAttributeEntriesException(final String message) {
|
||||
super(message, SpServerError.SP_ATTRIBUTES_TO_MANY_ENTRIES);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* Thrown if too many status entries have been inserted.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class ToManyStatusEntriesException extends SpServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new FileUploadFailedException with
|
||||
* {@link SpServerError#SP_REST_BODY_NOT_READABLE} error.
|
||||
*/
|
||||
public ToManyStatusEntriesException() {
|
||||
super(SpServerError.SP_ACTION_STATUS_TO_MANY_ENTRIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public ToManyStatusEntriesException(final Throwable cause) {
|
||||
super(SpServerError.SP_ACTION_STATUS_TO_MANY_ENTRIES, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public ToManyStatusEntriesException(final String message) {
|
||||
super(message, SpServerError.SP_ACTION_STATUS_TO_MANY_ENTRIES);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
|
||||
/**
|
||||
* Thrown if user tries to add a {@link SoftwareModule} to a
|
||||
* {@link DistributionSet} that is not defined by< the
|
||||
* {@link DistributionSetType}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class UnsupportedSoftwareModuleForThisDistributionSetException extends SpServerRtException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new UnsupportedSoftwareModuleForThisDistributionSetException
|
||||
* with {@link SpServerError#SP_DS_MODULE_UNSUPPORTED} error.
|
||||
*/
|
||||
public UnsupportedSoftwareModuleForThisDistributionSetException() {
|
||||
super(SpServerError.SP_DS_MODULE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* for the exception
|
||||
*/
|
||||
public UnsupportedSoftwareModuleForThisDistributionSetException(final Throwable cause) {
|
||||
super(SpServerError.SP_DS_MODULE_UNSUPPORTED, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* of the error
|
||||
*/
|
||||
public UnsupportedSoftwareModuleForThisDistributionSetException(final String message) {
|
||||
super(message, SpServerError.SP_DS_MODULE_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedAttributeNode;
|
||||
import javax.persistence.NamedEntityGraph;
|
||||
import javax.persistence.NamedEntityGraphs;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.eclipse.hawkbit.cache.CacheField;
|
||||
import org.eclipse.hawkbit.cache.CacheKeys;
|
||||
import org.eclipse.persistence.annotations.CascadeOnDelete;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Applicable transition changes of the software {@link SoftwareModule} state of
|
||||
* a {@link Target}, e.g. install, uninstall, update, start, stop, and
|
||||
* preparations for the transition change, i.e. download.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Actions are managed by the SP server (SPS) and applied to the edge controller
|
||||
* by the SP controller (SPC). Actions may also be value added commands that are
|
||||
* nor directly related to SP, e.g. factory reset.
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Table(name = "sp_action", indexes = { @Index(name = "sp_idx_action_01", columnList = "tenant,distribution_set"),
|
||||
@Index(name = "sp_idx_action_02", columnList = "tenant,target,active"),
|
||||
@Index(name = "sp_idx_action_prim", columnList = "tenant,id") })
|
||||
@NamedEntityGraphs({ @NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }),
|
||||
@NamedEntityGraph(name = "Action.all", attributeNodes = { @NamedAttributeNode("distributionSet"),
|
||||
@NamedAttributeNode("target") }) })
|
||||
@Entity
|
||||
public class Action extends BaseEntity implements Comparable<Action> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* indicating that target action has no force time {@link #hasForcedTime()}.
|
||||
*/
|
||||
public static final long NO_FORCE_TIME = 0L;
|
||||
|
||||
/**
|
||||
* the {@link DistributionSet} which should be installed by this action.
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_ds") )
|
||||
private DistributionSet distributionSet;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_target") )
|
||||
private Target target;
|
||||
|
||||
@Column(name = "active")
|
||||
private boolean active;
|
||||
|
||||
@Column(name = "action_type", nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private ActionType actionType;
|
||||
|
||||
@Column(name = "forced_time")
|
||||
private long forcedTime;
|
||||
|
||||
@Column(name = "status")
|
||||
private Status status;
|
||||
|
||||
@CascadeOnDelete
|
||||
@OneToMany(mappedBy = "action", targetEntity = ActionStatus.class, fetch = FetchType.LAZY, cascade = {
|
||||
CascadeType.REMOVE })
|
||||
private List<ActionStatus> actionStatus;
|
||||
|
||||
/**
|
||||
* Note: filled only in {@link Status#DOWNLOAD}.
|
||||
*/
|
||||
@Transient
|
||||
@CacheField(key = CacheKeys.DOWNLOAD_PROGRESS_PERCENT)
|
||||
private int downloadProgressPercent;
|
||||
|
||||
/**
|
||||
* @return the distributionSet
|
||||
*/
|
||||
public DistributionSet getDistributionSet() {
|
||||
return distributionSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param distributionSet
|
||||
* the distributionSet to set
|
||||
*/
|
||||
public void setDistributionSet(final DistributionSet distributionSet) {
|
||||
this.distributionSet = distributionSet;
|
||||
}
|
||||
|
||||
public boolean isCancelingOrCanceled() {
|
||||
return status == Status.CANCELING || status == Status.CANCELED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param active
|
||||
* the active to set
|
||||
*/
|
||||
public void setActive(final boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the status
|
||||
*/
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param status
|
||||
* the status to set
|
||||
*/
|
||||
public void setStatus(final Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the downloadProgressPercent
|
||||
*/
|
||||
public int getDownloadProgressPercent() {
|
||||
return downloadProgressPercent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param downloadProgressPercent
|
||||
* the downloadProgressPercent to set
|
||||
*/
|
||||
public void setDownloadProgressPercent(final int downloadProgressPercent) {
|
||||
this.downloadProgressPercent = downloadProgressPercent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the active
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param actionType
|
||||
* the actionType to set
|
||||
*/
|
||||
public void setActionType(final ActionType actionType) {
|
||||
this.actionType = actionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionType
|
||||
*/
|
||||
public ActionType getActionType() {
|
||||
return actionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionStatus
|
||||
*/
|
||||
public List<ActionStatus> getActionStatus() {
|
||||
return actionStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param target
|
||||
* the target to set
|
||||
*/
|
||||
public void setTarget(final Target target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the target
|
||||
*/
|
||||
public Target getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the forcedTime
|
||||
*/
|
||||
public long getForcedTime() {
|
||||
return forcedTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param forcedTime
|
||||
* the forcedTime to set
|
||||
*/
|
||||
public void setForcedTime(final long forcedTime) {
|
||||
this.forcedTime = forcedTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final Action o) {
|
||||
if (super.getId() == null || o == null || o.getId() == null) {
|
||||
return 0;
|
||||
}
|
||||
return super.getId().compareTo(o.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if the {@link #forcedTime} is hit by the given
|
||||
* {@code hitTimeMillis}, by means if the given milliseconds are greater
|
||||
* than the forcedTime.
|
||||
*
|
||||
* @param hitTimeMillis
|
||||
* the milliseconds, mostly the
|
||||
* {@link System#currentTimeMillis()}
|
||||
* @return {@code true} if this {@link #type} is in
|
||||
* {@link ActionType#TIMEFORCED} and the given {@code hitTimeMillis}
|
||||
* is greater than the {@link #forcedTime} otherwise {@code false}
|
||||
*/
|
||||
public boolean isHitAutoForceTime(final long hitTimeMillis) {
|
||||
if (actionType == ActionType.TIMEFORCED) {
|
||||
return hitTimeMillis >= forcedTime;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if either the {@link #type} is
|
||||
* {@link ActionType#FORCED} or {@link ActionType#TIMEFORCED} but
|
||||
* then if the {@link #forcedTime} has been exceeded otherwise
|
||||
* always {@code false}
|
||||
*/
|
||||
public boolean isForce() {
|
||||
switch (actionType) {
|
||||
case FORCED:
|
||||
return true;
|
||||
case TIMEFORCED:
|
||||
return isHitAutoForceTime(System.currentTimeMillis());
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the forced
|
||||
*/
|
||||
public boolean isForced() {
|
||||
return actionType == ActionType.FORCED;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Action [distributionSet=" + distributionSet + ", getId()=" + getId() + "]";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((actionType == null) ? 0 : actionType.hashCode());
|
||||
result = prime * result + (active ? 1231 : 1237);
|
||||
result = prime * result + (int) (forcedTime ^ (forcedTime >>> 32));
|
||||
result = prime * result + ((status == null) ? 0 : status.hashCode());
|
||||
result = prime * result + (isHitAutoForceTime(System.currentTimeMillis()) ? 1231 : 1237);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) { // NOSONAR - as this is generated
|
||||
// code
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Action other = (Action) obj;
|
||||
if (actionType != other.actionType) {
|
||||
return false;
|
||||
}
|
||||
if (active != other.active) {
|
||||
return false;
|
||||
}
|
||||
if (forcedTime != other.forcedTime) {
|
||||
return false;
|
||||
}
|
||||
if (status != other.status) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Action status as reported by the controller.
|
||||
*
|
||||
* Be aware that JPA is persiting the ordnial number of the enum by means
|
||||
* the ordered number in the enum. So don't re-order the enums within the
|
||||
* Status enum declaration!
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public enum Status {
|
||||
/**
|
||||
* Action is finished successfully for this target.
|
||||
*/
|
||||
FINISHED,
|
||||
|
||||
/**
|
||||
* Action has failed for this target.
|
||||
*/
|
||||
ERROR,
|
||||
|
||||
/**
|
||||
* Action is still running but with warnings.
|
||||
*/
|
||||
WARNING,
|
||||
|
||||
/**
|
||||
* Action is still running for this target.
|
||||
*/
|
||||
RUNNING,
|
||||
|
||||
/**
|
||||
* Action has been canceled for this target.
|
||||
*/
|
||||
CANCELED,
|
||||
|
||||
/**
|
||||
* Action is in canceling state and waiting for controller confirmation.
|
||||
*/
|
||||
CANCELING,
|
||||
|
||||
/**
|
||||
* Action has been presented to the target.
|
||||
*/
|
||||
RETRIEVED,
|
||||
|
||||
/**
|
||||
* Action needs download by this target which has now started.
|
||||
*/
|
||||
DOWNLOAD;
|
||||
}
|
||||
|
||||
/**
|
||||
* The action type for this action relation.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public enum ActionType {
|
||||
FORCED, SOFT, TIMEFORCED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedAttributeNode;
|
||||
import javax.persistence.NamedEntityGraph;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.persistence.annotations.CascadeOnDelete;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
/**
|
||||
* Entity to store the status for a specific action.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Table(name = "sp_action_status", indexes = { @Index(name = "sp_idx_action_status_01", columnList = "tenant,action"),
|
||||
@Index(name = "sp_idx_action_status_02", columnList = "tenant,action,status"),
|
||||
@Index(name = "sp_idx_action_status_prim", columnList = "tenant,id") })
|
||||
@NamedEntityGraph(name = "ActionStatus.withMessages", attributeNodes = { @NamedAttributeNode("messages") })
|
||||
@Entity
|
||||
public class ActionStatus extends BaseEntity {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "target_occurred_at")
|
||||
private Long occurredAt;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||
@JoinColumn(name = "action", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_act_stat_action") )
|
||||
private Action action;
|
||||
|
||||
@Column(name = "status")
|
||||
private Status status;
|
||||
|
||||
@CascadeOnDelete
|
||||
@ElementCollection(fetch = FetchType.LAZY, targetClass = String.class)
|
||||
@CollectionTable(name = "sp_action_status_messages", joinColumns = @JoinColumn(name = "action_status_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_stat_msg_act_stat") ) , indexes = {
|
||||
@Index(name = "sp_idx_action_status_msgs_01", columnList = "action_status_id") })
|
||||
@Column(name = "detail_message", length = 512)
|
||||
private final List<String> messages = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link ActionStatus} object.
|
||||
*
|
||||
* @param action
|
||||
* the action for this action status
|
||||
* @param status
|
||||
* the status for this action status
|
||||
* @param occurredAt
|
||||
* the occurred timestamp
|
||||
*/
|
||||
public ActionStatus(final Action action, final Status status, final Long occurredAt) {
|
||||
this.action = action;
|
||||
this.status = status;
|
||||
this.occurredAt = occurredAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ActionStatus} object.
|
||||
*
|
||||
* @param action
|
||||
* the action for this action status
|
||||
* @param status
|
||||
* the status for this action status
|
||||
* @param occurredAt
|
||||
* the occurred timestamp
|
||||
* @param messages
|
||||
* the messages which should be added to this action status
|
||||
*/
|
||||
public ActionStatus(final Action action, final Status status, final Long occurredAt, final String... messages) {
|
||||
this.action = action;
|
||||
this.status = status;
|
||||
this.occurredAt = occurredAt;
|
||||
for (final String msg : messages) {
|
||||
addMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public ActionStatus() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the occurredAt
|
||||
*/
|
||||
public Long getOccurredAt() {
|
||||
return occurredAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param occurredAt
|
||||
* the occurredAt to set
|
||||
*/
|
||||
public void setOccurredAt(final Long occurredAt) {
|
||||
this.occurredAt = occurredAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds message.
|
||||
*
|
||||
* @param message
|
||||
* to add
|
||||
*/
|
||||
public final void addMessage(final String message) {
|
||||
Splitter.fixedLength(512).split(message).forEach(chunk -> messages.add(chunk));
|
||||
}
|
||||
|
||||
public List<String> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the action
|
||||
*/
|
||||
public Action getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param action
|
||||
* the action to set
|
||||
*/
|
||||
public void setAction(final Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the status
|
||||
*/
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param status
|
||||
* the status to set
|
||||
*/
|
||||
public void setStatus(final Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
|
||||
/**
|
||||
* Custom JPA Model for querying {@link Action} include the count of the
|
||||
* action's {@link ActionStatus}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ActionWithStatusCount {
|
||||
private final Long actionStatusCount;
|
||||
private final Long actionId;
|
||||
private final ActionType actionType;
|
||||
private final boolean actionActive;
|
||||
private final long actionForceTime;
|
||||
private final Status actionStatus;
|
||||
private final Long actionCreatedAt;
|
||||
private final Long actionLastModifiedAt;
|
||||
private final Long dsId;
|
||||
private final String dsName;
|
||||
private final String dsVersion;
|
||||
private final Action action;
|
||||
|
||||
/**
|
||||
* JPA constructor, the parameter are the result set columns of the custom
|
||||
* query.
|
||||
*
|
||||
* @param actionId
|
||||
* the ID of the action
|
||||
* @param actionType
|
||||
* the action type
|
||||
* @param active
|
||||
* the active attribute of the action
|
||||
* @param forcedTime
|
||||
* the forced time attribute of the action
|
||||
* @param status
|
||||
* the status attribute of the action
|
||||
* @param actionCreatedAt
|
||||
* the createdAt timestamp of the action
|
||||
* @param actionLastModifiedAt
|
||||
* the last modified timestamp of the action
|
||||
* @param dsId
|
||||
* the ID of the distributionset
|
||||
* @param dsName
|
||||
* the name of the distributionset
|
||||
* @param dsVersion
|
||||
* the version of the distributionset
|
||||
* @param actionStatusCount
|
||||
* the count of the action status for this action
|
||||
*/
|
||||
public ActionWithStatusCount(final Long actionId, final ActionType actionType, final boolean active,
|
||||
final long forcedTime, final Status status, final Long actionCreatedAt, final Long actionLastModifiedAt,
|
||||
final Long dsId, final String dsName, final String dsVersion, final Long actionStatusCount) {
|
||||
this.actionId = actionId;
|
||||
this.actionType = actionType;
|
||||
this.actionActive = active;
|
||||
this.actionForceTime = forcedTime;
|
||||
this.actionStatus = status;
|
||||
this.actionCreatedAt = actionCreatedAt;
|
||||
this.actionLastModifiedAt = actionLastModifiedAt;
|
||||
this.dsId = dsId;
|
||||
this.dsName = dsName;
|
||||
this.dsVersion = dsVersion;
|
||||
this.actionStatusCount = actionStatusCount;
|
||||
|
||||
this.action = new Action();
|
||||
this.action.setActionType(actionType);
|
||||
this.action.setActive(actionActive);
|
||||
this.action.setForcedTime(actionForceTime);
|
||||
this.action.setStatus(actionStatus);
|
||||
this.action.setId(actionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the action
|
||||
*/
|
||||
public Action getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionId
|
||||
*/
|
||||
public Long getActionId() {
|
||||
return actionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionType
|
||||
*/
|
||||
public ActionType getActionType() {
|
||||
return actionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionActive
|
||||
*/
|
||||
public boolean isActionActive() {
|
||||
return actionActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionForceTime
|
||||
*/
|
||||
public long getActionForceTime() {
|
||||
return actionForceTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionStatus
|
||||
*/
|
||||
public Status getActionStatus() {
|
||||
return actionStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionCreatedAt
|
||||
*/
|
||||
public Long getActionCreatedAt() {
|
||||
return actionCreatedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionLastModifiedAt
|
||||
*/
|
||||
public Long getActionLastModifiedAt() {
|
||||
return actionLastModifiedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dsId
|
||||
*/
|
||||
public Long getDsId() {
|
||||
return dsId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dsName
|
||||
*/
|
||||
public String getDsName() {
|
||||
return dsName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dsVersion
|
||||
*/
|
||||
public String getDsVersion() {
|
||||
return dsVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actionStatusCount
|
||||
*/
|
||||
public Long getActionStatusCount() {
|
||||
return actionStatusCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
* Tenant specific locally stored artifact representation that is used by
|
||||
* {@link SoftwareModule} .
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class Artifact extends BaseEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "sha1_hash", length = 40, nullable = true)
|
||||
private String sha1Hash;
|
||||
|
||||
@Column(name = "md5_hash", length = 32, nullable = true)
|
||||
private String md5Hash;
|
||||
|
||||
@Column(name = "file_size")
|
||||
private Long size;
|
||||
|
||||
public abstract SoftwareModule getSoftwareModule();
|
||||
|
||||
/**
|
||||
* @return the md5Hash
|
||||
*/
|
||||
public String getMd5Hash() {
|
||||
return md5Hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sha1Hash
|
||||
*/
|
||||
public String getSha1Hash() {
|
||||
return sha1Hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param md5Hash
|
||||
* the md5Hash to set
|
||||
*/
|
||||
public void setMd5Hash(final String md5Hash) {
|
||||
this.md5Hash = md5Hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sha1Hash
|
||||
* the sha1Hash to set
|
||||
*/
|
||||
public void setSha1Hash(final String sha1Hash) {
|
||||
this.sha1Hash = sha1Hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size
|
||||
*/
|
||||
public Long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param size
|
||||
* the size to set
|
||||
*/
|
||||
public void setSize(final Long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.EntityListeners;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.PrePersist;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.eclipse.hawkbit.eventbus.CacheFieldEntityListener;
|
||||
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
|
||||
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.TenantAwareHolder;
|
||||
import org.eclipse.persistence.annotations.Multitenant;
|
||||
import org.eclipse.persistence.annotations.MultitenantType;
|
||||
import org.eclipse.persistence.annotations.TenantDiscriminatorColumn;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
import org.springframework.hateoas.Identifiable;
|
||||
|
||||
/**
|
||||
* Holder of all base attributes common to all entities.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@MappedSuperclass
|
||||
@Access(AccessType.FIELD)
|
||||
@EntityListeners({ AuditingEntityListener.class, CacheFieldEntityListener.class })
|
||||
@TenantDiscriminatorColumn(name = "tenant", length = 40)
|
||||
@Multitenant(MultitenantType.SINGLE_TABLE)
|
||||
public abstract class BaseEntity implements Serializable, Identifiable<Long> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
|
||||
private String createdBy;
|
||||
private String lastModifiedBy;
|
||||
private Long createdAt;
|
||||
private Long lastModifiedAt;
|
||||
|
||||
@Version
|
||||
@Column(name = "optlock_revision")
|
||||
private long optLockRevision;
|
||||
|
||||
@Column(name = "tenant", nullable = false, insertable = false, updatable = false, length = 40)
|
||||
private String tenant;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public BaseEntity() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entity
|
||||
* the entity to copy
|
||||
*/
|
||||
public BaseEntity(final BaseEntity entity) {
|
||||
id = entity.id;
|
||||
createdAt = entity.createdAt;
|
||||
createdBy = entity.createdBy;
|
||||
lastModifiedAt = entity.lastModifiedAt;
|
||||
lastModifiedBy = entity.lastModifiedBy;
|
||||
optLockRevision = entity.optLockRevision;
|
||||
}
|
||||
|
||||
/**
|
||||
* PrePersist listener method for all {@link BaseEntity} entities.
|
||||
*/
|
||||
@PrePersist
|
||||
public void prePersist() {
|
||||
// before persisting the entity check the current ID of the tenant by
|
||||
// using the TenantAware
|
||||
// service
|
||||
final String currentTenant = SystemManagementHolder.getInstance().currentTenant();
|
||||
if (currentTenant == null) {
|
||||
throw new TenantNotExistException(
|
||||
"Tenant " + TenantAwareHolder.getInstance().getTenantAware().getCurrentTenant()
|
||||
+ " does not exists, cannot create entity " + this.getClass() + " with id " + id);
|
||||
}
|
||||
setTenant(currentTenant.toUpperCase());
|
||||
}
|
||||
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Column(name = "created_at", insertable = true, updatable = false)
|
||||
public Long getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Column(name = "created_by", insertable = true, updatable = false, length = 40)
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Column(name = "last_modified_at", insertable = false, updatable = true)
|
||||
public Long getLastModifiedAt() {
|
||||
return lastModifiedAt;
|
||||
}
|
||||
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Column(name = "last_modified_by", insertable = false, updatable = true, length = 40)
|
||||
public String getLastModifiedBy() {
|
||||
return lastModifiedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param createdBy
|
||||
* the createdBy to set
|
||||
*/
|
||||
@CreatedBy
|
||||
public void setCreatedBy(final String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lastModifiedBy
|
||||
* the lastModifiedBy to set
|
||||
*/
|
||||
@LastModifiedBy
|
||||
public void setLastModifiedBy(final String lastModifiedBy) {
|
||||
this.lastModifiedBy = lastModifiedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param createdAt
|
||||
* the createdAt to set
|
||||
*/
|
||||
@CreatedDate
|
||||
public void setCreatedAt(final Long createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lastModifiedAt
|
||||
* the lastModifiedAt to set
|
||||
*/
|
||||
@LastModifiedDate
|
||||
public void setLastModifiedAt(final Long lastModifiedAt) {
|
||||
this.lastModifiedAt = lastModifiedAt;
|
||||
}
|
||||
|
||||
public long getOptLockRevision() {
|
||||
return optLockRevision;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tenant
|
||||
*/
|
||||
public String getTenant() {
|
||||
return tenant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tenant
|
||||
* the tenant to set
|
||||
*/
|
||||
public void setTenant(final String tenant) {
|
||||
this.tenant = tenant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
@Override
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BaseEntity [id=" + id + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* the id to set
|
||||
*/
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() { // NOSONAR - as this is generated code
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (id == null ? 0 : id.hashCode());
|
||||
result = prime * result + (int) (optLockRevision ^ optLockRevision >>> 32);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) { // NOSONAR - as this is generated
|
||||
// code
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final BaseEntity other = (BaseEntity) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (optLockRevision != other.optLockRevision) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Use to display software modules for the selected distribution.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class CustomSoftwareModule implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 6144585781451168439L;
|
||||
|
||||
private final SoftwareModule softwareModule;
|
||||
|
||||
private final boolean assigned;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param softwareModule
|
||||
* entity.
|
||||
* @param assigned
|
||||
* as true if the software module is assigned and false if not
|
||||
* assigned.
|
||||
*/
|
||||
public CustomSoftwareModule(final SoftwareModule softwareModule, final boolean assigned) {
|
||||
this.softwareModule = softwareModule;
|
||||
this.assigned = assigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the softwareModule
|
||||
*/
|
||||
public SoftwareModule getSoftwareModule() {
|
||||
return softwareModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the assigned
|
||||
*/
|
||||
public boolean isAssigned() {
|
||||
return assigned;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedAttributeNode;
|
||||
import javax.persistence.NamedEntityGraph;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException;
|
||||
import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException;
|
||||
import org.eclipse.persistence.annotations.CascadeOnDelete;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The {@link DistributionSet} is defined in the SP repository and contains at
|
||||
* least an OS and an Agent Hub.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A {@link Target} has exactly one target {@link DistributionSet} assigned.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "sp_distribution_set", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = { "name", "version", "tenant" }, name = "uk_distrib_set") }, indexes = {
|
||||
@Index(name = "sp_idx_distribution_set_01", columnList = "tenant,deleted,name,complete"),
|
||||
@Index(name = "sp_idx_distribution_set_02", columnList = "tenant,required_migration_step"),
|
||||
@Index(name = "sp_idx_distribution_set_prim", columnList = "tenant,id") })
|
||||
@NamedEntityGraph(name = "DistributionSet.detail", attributeNodes = { @NamedAttributeNode("modules"),
|
||||
@NamedAttributeNode("tags"), @NamedAttributeNode("type") })
|
||||
public class DistributionSet extends NamedVersionedEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "required_migration_step")
|
||||
private boolean requiredMigrationStep = false;
|
||||
|
||||
@ManyToMany(targetEntity = SoftwareModule.class, fetch = FetchType.LAZY)
|
||||
@JoinTable(name = "sp_ds_module", joinColumns = {
|
||||
@JoinColumn(name = "ds_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_ds") ) }, inverseJoinColumns = {
|
||||
@JoinColumn(name = "module_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_module") ) })
|
||||
private final Set<SoftwareModule> modules = new HashSet<SoftwareModule>();
|
||||
|
||||
@ManyToMany(targetEntity = DistributionSetTag.class)
|
||||
@JoinTable(name = "sp_ds_dstag", joinColumns = {
|
||||
@JoinColumn(name = "ds", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_ds") ) }, inverseJoinColumns = {
|
||||
@JoinColumn(name = "TAG", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_tag") ) })
|
||||
private Set<DistributionSetTag> tags = new HashSet<DistributionSetTag>();
|
||||
|
||||
@Column(name = "deleted")
|
||||
private boolean deleted = false;
|
||||
|
||||
@OneToMany(mappedBy = "assignedDistributionSet", targetEntity = Target.class, fetch = FetchType.LAZY)
|
||||
private List<Target> assignedToTargets;
|
||||
|
||||
@OneToMany(mappedBy = "installedDistributionSet", targetEntity = TargetInfo.class, fetch = FetchType.LAZY)
|
||||
private List<TargetInfo> installedAtTargets;
|
||||
|
||||
@OneToMany(mappedBy = "distributionSet", targetEntity = Action.class, fetch = FetchType.LAZY)
|
||||
private List<Action> actions;
|
||||
|
||||
@CascadeOnDelete
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE })
|
||||
@JoinColumn(name = "ds_id", insertable = false, updatable = false)
|
||||
private final List<DistributionSetMetadata> metadata = new ArrayList<>();
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "ds_id", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstype_ds") )
|
||||
private DistributionSetType type;
|
||||
|
||||
@Column(name = "complete")
|
||||
private boolean complete = false;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public DistributionSet() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param name
|
||||
* of the {@link DistributionSet}
|
||||
* @param version
|
||||
* of the {@link DistributionSet}
|
||||
* @param description
|
||||
* of the {@link DistributionSet}
|
||||
* @param type
|
||||
* of the {@link DistributionSet}
|
||||
* @param moduleList
|
||||
* {@link SoftwareModule}s of the {@link DistributionSet}
|
||||
*/
|
||||
public DistributionSet(final String name, final String version, final String description,
|
||||
final DistributionSetType type, final Iterable<SoftwareModule> moduleList) {
|
||||
super(name, version, description);
|
||||
|
||||
this.type = type;
|
||||
if (moduleList != null) {
|
||||
moduleList.forEach(module -> addModule(module));
|
||||
}
|
||||
complete = type.checkComplete(this);
|
||||
}
|
||||
|
||||
public Set<DistributionSetTag> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deleted
|
||||
*/
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the metadata
|
||||
*/
|
||||
public List<DistributionSetMetadata> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actions
|
||||
*/
|
||||
public List<Action> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + this.getClass().getName().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof DistributionSet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isRequiredMigrationStep() {
|
||||
return requiredMigrationStep;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param deleted
|
||||
* the deleted to set
|
||||
*/
|
||||
public DistributionSet setDeleted(final boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DistributionSet setRequiredMigrationStep(final boolean isRequiredMigrationStep) {
|
||||
requiredMigrationStep = isRequiredMigrationStep;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tags
|
||||
* the tags to set
|
||||
*/
|
||||
public DistributionSet setTags(final Set<DistributionSetTag> tags) {
|
||||
this.tags = tags;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the assignedTargets
|
||||
*/
|
||||
public List<Target> getAssignedTargets() {
|
||||
return assignedToTargets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the installedTargets
|
||||
*/
|
||||
public List<TargetInfo> getInstalledTargets() {
|
||||
return installedAtTargets;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DistributionSet [getName()=" + getName() + ", getOptLockRevision()=" + getOptLockRevision()
|
||||
+ ", getId()=" + getId() + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return unmodifiableSet of {@link SoftwareModule}.
|
||||
*/
|
||||
public Set<SoftwareModule> getModules() {
|
||||
return Collections.unmodifiableSet(modules);
|
||||
}
|
||||
|
||||
public DistributionSetIdName getDistributionSetIdName() {
|
||||
return new DistributionSetIdName(getId(), getName(), getVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareModule
|
||||
* @return <code>true</code> if the module was added and <code>false</code>
|
||||
* if it already existed in the set
|
||||
*
|
||||
*/
|
||||
public boolean addModule(final SoftwareModule softwareModule) {
|
||||
|
||||
// we cannot allow that modules are added without a type defined
|
||||
if (type == null) {
|
||||
throw new DistributionSetTypeUndefinedException();
|
||||
}
|
||||
|
||||
// check if it is allowed to such a module to this DS type
|
||||
if (!type.containsModuleType(softwareModule.getType())) {
|
||||
throw new UnsupportedSoftwareModuleForThisDistributionSetException();
|
||||
}
|
||||
|
||||
final Optional<SoftwareModule> found = modules.stream()
|
||||
.filter(module -> module.getId().equals(softwareModule.getId())).findFirst();
|
||||
|
||||
if (found.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final long allready = modules.stream()
|
||||
.filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).count();
|
||||
|
||||
if (allready >= softwareModule.getType().getMaxAssignments()) {
|
||||
final Optional<SoftwareModule> sameKey = modules.stream()
|
||||
.filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).findFirst();
|
||||
modules.remove(sameKey.get());
|
||||
}
|
||||
|
||||
if (modules.add(softwareModule)) {
|
||||
complete = type.checkComplete(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removed given {@link SoftwareModule} from this DS instance.
|
||||
*
|
||||
* @param softwareModule
|
||||
* to remove
|
||||
* @return <code>true</code> if element was found and removed
|
||||
*/
|
||||
public boolean removeModule(final SoftwareModule softwareModule) {
|
||||
final Optional<SoftwareModule> found = modules.stream()
|
||||
.filter(module -> module.getId().equals(softwareModule.getId())).findFirst();
|
||||
|
||||
if (found.isPresent()) {
|
||||
modules.remove(found.get());
|
||||
complete = type.checkComplete(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches through modules for the given type.
|
||||
*
|
||||
* @param type
|
||||
* to serach for
|
||||
* @return SoftwareModule of giben type or <code>null</code> if not in the
|
||||
* list.
|
||||
*/
|
||||
public SoftwareModule findFirstModuleByType(final SoftwareModuleType type) {
|
||||
final Optional<SoftwareModule> result = modules.stream().filter(module -> module.getType().equals(type))
|
||||
.findFirst();
|
||||
|
||||
if (result.isPresent()) {
|
||||
return result.get();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public DistributionSetType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* the type to set
|
||||
*/
|
||||
public void setType(final DistributionSetType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the complete
|
||||
*/
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class DistributionSetIdName implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Long id;
|
||||
private final String name;
|
||||
private final String version;
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* the {@link DistributionSet#getId()}
|
||||
* @param name
|
||||
* the {@link DistributionSet#getName()}
|
||||
* @param version
|
||||
* the {@link DistributionSet#getVersion()}
|
||||
*
|
||||
*/
|
||||
public DistributionSetIdName(final Long id, final String name, final String version) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() { // NOSONAR - as this is generated
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (id == null ? 0 : id.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) { // NOSONAR - as this is generated
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final DistributionSetIdName other = (DistributionSetIdName) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
// only return the ID because it's used in vaadin for setting the item
|
||||
// id in the dom
|
||||
return id.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* Metadata for {@link DistributionSet}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@IdClass(DsMetadataCompositeKey.class)
|
||||
@Entity
|
||||
@Table(name = "sp_ds_metadata")
|
||||
public class DistributionSetMetadata implements Serializable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@Column(name = "meta_key", length = 128)
|
||||
private String key;
|
||||
|
||||
@Column(name = "meta_value", length = 4000)
|
||||
@Basic
|
||||
private String value;
|
||||
|
||||
@Id
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "ds_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_metadata_ds") )
|
||||
private DistributionSet distributionSet;
|
||||
|
||||
public DistributionSetMetadata() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter constructor.
|
||||
*
|
||||
* @param key
|
||||
* @param distributionSet
|
||||
* @param value
|
||||
*/
|
||||
public DistributionSetMetadata(final String key, final DistributionSet distributionSet, final String value) {
|
||||
this.key = key;
|
||||
this.distributionSet = distributionSet;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public DsMetadataCompositeKey getId() {
|
||||
return new DsMetadataCompositeKey(distributionSet, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the key
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* the key to set
|
||||
*/
|
||||
public void setKey(final String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param distributionSet
|
||||
* the distributionSet to set
|
||||
*/
|
||||
public void setDistributionSet(final DistributionSet distributionSet) {
|
||||
this.distributionSet = distributionSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* the value to set
|
||||
*/
|
||||
public void setValue(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the distributionSet
|
||||
*/
|
||||
public DistributionSet getDistributionSet() {
|
||||
return distributionSet;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
/**
|
||||
* A {@link DistributionSetTag} is used to describe DistributionSet attributes
|
||||
* and use them also for filtering the DistributionSet list.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "sp_distributionset_tag", indexes = {
|
||||
@Index(name = "sp_idx_distribution_set_tag_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = {
|
||||
"name", "tenant" }, name = "uk_ds_tag") )
|
||||
public class DistributionSetTag extends Tag {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
* @param name
|
||||
* of the {@link DistributionSetTag}
|
||||
**/
|
||||
public DistributionSetTag(final String name) {
|
||||
super(name, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
* @param name
|
||||
* of the {@link DistributionSetTag}
|
||||
* @param description
|
||||
* of the {@link DistributionSetTag}
|
||||
* @param colour
|
||||
* of tag in UI
|
||||
*/
|
||||
public DistributionSetTag(final String name, final String description, final String colour) {
|
||||
super(name, description, colour);
|
||||
}
|
||||
|
||||
DistributionSetTag() {
|
||||
super();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + this.getClass().getName().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof DistributionSetTag)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
/**
|
||||
* A distribution set type defines which software module types can or have to be
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "sp_distribution_set_type", indexes = {
|
||||
@Index(name = "sp_idx_distribution_set_type_01", columnList = "tenant,deleted"),
|
||||
@Index(name = "sp_idx_distribution_set_type_prim", columnList = "tenant,id") }, uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = { "name", "tenant" }, name = "uk_dst_name"),
|
||||
@UniqueConstraint(columnNames = { "type_key", "tenant" }, name = "uk_dst_key") })
|
||||
public class DistributionSetType extends NamedEntity {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@OneToMany(targetEntity = DistributionSetTypeElement.class, cascade = {
|
||||
CascadeType.ALL }, fetch = FetchType.EAGER, orphanRemoval = true)
|
||||
@JoinColumn(name = "distribution_set_type", insertable = false, updatable = false)
|
||||
private final Set<DistributionSetTypeElement> elements = new HashSet<>();
|
||||
|
||||
@Column(name = "type_key", nullable = false, length = 64)
|
||||
private String key;
|
||||
|
||||
@Column(name = "colour", nullable = true, length = 16)
|
||||
private String colour;
|
||||
|
||||
@Column(name = "deleted")
|
||||
private boolean deleted = false;
|
||||
|
||||
public DistributionSetType() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard constructor.
|
||||
*
|
||||
* @param key
|
||||
* of the type (unique)
|
||||
* @param name
|
||||
* of the type (unique)
|
||||
* @param description
|
||||
* of the type
|
||||
*/
|
||||
public DistributionSetType(final String key, final String name, final String description) {
|
||||
this(key, name, description, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param key
|
||||
* of the type
|
||||
* @param name
|
||||
* of the type
|
||||
* @param description
|
||||
* of the type
|
||||
* @param color
|
||||
* of the type. It will be null by default
|
||||
*/
|
||||
public DistributionSetType(final String key, final String name, final String description, final String color) {
|
||||
super(name, description);
|
||||
this.key = key;
|
||||
this.colour = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deleted
|
||||
*/
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param deleted
|
||||
* the deleted to set
|
||||
*/
|
||||
public void setDeleted(final boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public Set<SoftwareModuleType> getMandatoryModuleTypes() {
|
||||
return elements.stream().filter(element -> element.isMandatory()).map(element -> element.getSmType())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<SoftwareModuleType> getOptionalModuleTypes() {
|
||||
return elements.stream().filter(element -> !element.isMandatory()).map(element -> element.getSmType())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given {@link SoftwareModuleType} is in this
|
||||
* {@link DistributionSetType}.
|
||||
*
|
||||
* @param softwareModuleType
|
||||
* search for
|
||||
* @return <code>true</code> if found
|
||||
*/
|
||||
public boolean containsModuleType(final SoftwareModuleType softwareModuleType) {
|
||||
for (final DistributionSetTypeElement distributionSetTypeElement : elements) {
|
||||
if (distributionSetTypeElement.getSmType().equals(softwareModuleType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given {@link SoftwareModuleType} is in this
|
||||
* {@link DistributionSetType} and defined as
|
||||
* {@link DistributionSetTypeElement#isMandatory()}.
|
||||
*
|
||||
* @param softwareModuleType
|
||||
* search for
|
||||
* @return <code>true</code> if found
|
||||
*/
|
||||
public boolean containsMandatoryModuleType(final SoftwareModuleType softwareModuleType) {
|
||||
return elements.stream().filter(element -> element.isMandatory())
|
||||
.filter(element -> element.getSmType().equals(softwareModuleType)).findFirst().isPresent();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given {@link SoftwareModuleType} is in this
|
||||
* {@link DistributionSetType} and NOT defined as
|
||||
* {@link DistributionSetTypeElement#isMandatory()}.
|
||||
*
|
||||
* @param softwareModuleType
|
||||
* search for
|
||||
* @return <code>true</code> if found
|
||||
*/
|
||||
public boolean containsOptionalModuleType(final SoftwareModuleType softwareModuleType) {
|
||||
return elements.stream().filter(element -> !element.isMandatory())
|
||||
.filter(element -> element.getSmType().equals(softwareModuleType)).findFirst().isPresent();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the modules of this {@link DistributionSetType} and the given
|
||||
* one.
|
||||
*
|
||||
* @param dsType
|
||||
* to compare with
|
||||
* @return <code>true</code> if the lists are identical.
|
||||
*/
|
||||
public boolean areModuleEntriesIdentical(final DistributionSetType dsType) {
|
||||
return new HashSet<DistributionSetTypeElement>(dsType.elements).equals(elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@link SoftwareModuleType} that is optional for the
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @param smType
|
||||
* to add
|
||||
* @return updated instance
|
||||
*/
|
||||
public DistributionSetType addOptionalModuleType(final SoftwareModuleType smType) {
|
||||
elements.add(new DistributionSetTypeElement(this, smType, false));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@link SoftwareModuleType} that is mandatory for the
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @param smType
|
||||
* to add
|
||||
* @return updated instance
|
||||
*/
|
||||
public DistributionSetType addMandatoryModuleType(final SoftwareModuleType smType) {
|
||||
elements.add(new DistributionSetTypeElement(this, smType, true));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes {@link SoftwareModuleType} from the list.
|
||||
*
|
||||
* @param smTypeId
|
||||
* to remove
|
||||
* @return updated instance
|
||||
*/
|
||||
public DistributionSetType removeModuleType(final Long smTypeId) {
|
||||
// we search by id (standard equals compares also revison)
|
||||
final Optional<DistributionSetTypeElement> found = elements.stream()
|
||||
.filter(element -> element.getSmType().getId().equals(smTypeId)).findFirst();
|
||||
|
||||
if (found.isPresent()) {
|
||||
elements.remove(found.get());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the key
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* the key to set
|
||||
*/
|
||||
public void setKey(final String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param distributionSet
|
||||
* to check for completeness
|
||||
* @return <code>true</code> if the all mandatory software module types are
|
||||
* in the system.
|
||||
*/
|
||||
public boolean checkComplete(final DistributionSet distributionSet) {
|
||||
return distributionSet.getModules().stream().map(module -> module.getType()).collect(Collectors.toList())
|
||||
.containsAll(getMandatoryModuleTypes());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the DistributionSet type color
|
||||
*/
|
||||
public String getColour() {
|
||||
return colour;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param colour
|
||||
* the col
|
||||
*/
|
||||
public void setColour(final String colour) {
|
||||
this.colour = colour;
|
||||
}
|
||||
|
||||
public Set<DistributionSetTypeElement> getElements() {
|
||||
return elements;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DistributionSetType [key=" + key + ", isDeleted()=" + isDeleted() + ", getId()=" + getId() + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.MapsId;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* Relation element between a {@link DistributionSetType} and its
|
||||
* {@link SoftwareModuleType} elements.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "sp_ds_type_element")
|
||||
public class DistributionSetTypeElement implements Serializable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@EmbeddedId
|
||||
private DistributionSetTypeElementCompositeKey key;
|
||||
|
||||
@Column(name = "mandatory")
|
||||
private boolean mandatory;
|
||||
|
||||
@MapsId("dsType")
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "distribution_set_type", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_type_element_dstype") )
|
||||
private DistributionSetType dsType;
|
||||
|
||||
@MapsId("smType")
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "software_module_type", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_type_element_smtype") )
|
||||
private SoftwareModuleType smType;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public DistributionSetTypeElement() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard constructor.
|
||||
*
|
||||
* @param dsType
|
||||
* of the element
|
||||
* @param smType
|
||||
* of the element
|
||||
* @param mandatory
|
||||
* to <code>true</code> if the {@link SoftwareModuleType} if
|
||||
* mandatory element in the {@link DistributionSet}.
|
||||
*/
|
||||
public DistributionSetTypeElement(final DistributionSetType dsType, final SoftwareModuleType smType,
|
||||
final boolean mandatory) {
|
||||
super();
|
||||
this.key = new DistributionSetTypeElementCompositeKey(dsType, smType);
|
||||
this.dsType = dsType;
|
||||
this.smType = smType;
|
||||
this.mandatory = mandatory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mandatory
|
||||
*/
|
||||
public boolean isMandatory() {
|
||||
return mandatory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dsType
|
||||
*/
|
||||
public DistributionSetType getDsType() {
|
||||
return dsType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the smType
|
||||
*/
|
||||
public SoftwareModuleType getSmType() {
|
||||
return smType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the key
|
||||
*/
|
||||
public DistributionSetTypeElementCompositeKey getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
|
||||
/**
|
||||
* Composite key for {@link DistributionSetTypeElement}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Embeddable
|
||||
public class DistributionSetTypeElementCompositeKey implements Serializable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "distribution_set_type", nullable = false)
|
||||
private Long dsType;
|
||||
|
||||
@Column(name = "software_module_type", nullable = false)
|
||||
private Long smType;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
DistributionSetTypeElementCompositeKey() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param dsType
|
||||
* in the key
|
||||
* @param smType
|
||||
* in the key
|
||||
*/
|
||||
DistributionSetTypeElementCompositeKey(final DistributionSetType dsType, final SoftwareModuleType smType) {
|
||||
super();
|
||||
this.dsType = dsType.getId();
|
||||
this.smType = smType.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dsType
|
||||
*/
|
||||
public Long getDsType() {
|
||||
return dsType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dsType
|
||||
* the dsType to set
|
||||
*/
|
||||
public void setDsType(final Long dsType) {
|
||||
this.dsType = dsType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the smType
|
||||
*/
|
||||
public Long getSmType() {
|
||||
return smType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param smType
|
||||
* the smType to set
|
||||
*/
|
||||
public void setSmType(final Long smType) {
|
||||
this.smType = smType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* The DistributionSet Metadata composite key which contains the meta data key
|
||||
* and the ID of the DistributionSet itself.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class DsMetadataCompositeKey implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String key;
|
||||
|
||||
private Long distributionSet;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public DsMetadataCompositeKey() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param distributionSet
|
||||
* the distribution set for this meta data
|
||||
* @param key
|
||||
* the key of the meta data
|
||||
*/
|
||||
public DsMetadataCompositeKey(final DistributionSet distributionSet, final String key) {
|
||||
this.distributionSet = distributionSet.getId();
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the key
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* the key to set
|
||||
*/
|
||||
public void setKey(final String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the distributionSet
|
||||
*/
|
||||
public Long getDistributionSet() {
|
||||
return distributionSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param distributionSet
|
||||
* the distributionSet to set
|
||||
*/
|
||||
public void setDistributionSet(final Long distributionSet) {
|
||||
this.distributionSet = distributionSet;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((distributionSet == null) ? 0 : distributionSet.hashCode());
|
||||
result = prime * result + ((key == null) ? 0 : key.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) { // NOSONAR - as this is generated
|
||||
// code
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final DsMetadataCompositeKey other = (DsMetadataCompositeKey) obj;
|
||||
if (distributionSet == null) {
|
||||
if (other.distributionSet != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!distributionSet.equals(other.distributionSet)) {
|
||||
return false;
|
||||
}
|
||||
if (key == null) {
|
||||
if (other.key != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!key.equals(other.key)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* External artifact representation with all the necessray informattion to
|
||||
* generate an artifact {@link URL} at runtime.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Table(name = "sp_external_artifact", indexes = {
|
||||
@Index(name = "sp_idx_external_artifact_prim", columnList = "id,tenant") })
|
||||
@Entity
|
||||
public class ExternalArtifact extends Artifact {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "provider", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_art_to_ext_provider") )
|
||||
private ExternalArtifactProvider externalArtifactProvider;
|
||||
|
||||
@Column(name = "url_suffix", length = 512)
|
||||
private String urlSuffix;
|
||||
|
||||
// CascadeType.PERSIST as we register ourself at the BSM
|
||||
@ManyToOne(optional = false, cascade = { CascadeType.PERSIST })
|
||||
@JoinColumn(name = "software_module", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_external_assigned_sm") )
|
||||
private SoftwareModule softwareModule;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public ExternalArtifact() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs {@link ExternalArtifact}.
|
||||
*
|
||||
* @param externalArtifactProvider
|
||||
* of the artifact
|
||||
* @param urlSuffix
|
||||
* of the artifact
|
||||
* @param softwareModule
|
||||
* of the artifact
|
||||
*/
|
||||
public ExternalArtifact(@NotNull final ExternalArtifactProvider externalArtifactProvider, final String urlSuffix,
|
||||
final SoftwareModule softwareModule) {
|
||||
setSoftwareModule(softwareModule);
|
||||
this.externalArtifactProvider = externalArtifactProvider;
|
||||
|
||||
if (urlSuffix != null) {
|
||||
this.urlSuffix = urlSuffix;
|
||||
} else {
|
||||
this.urlSuffix = externalArtifactProvider.getDefaultSuffix();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the softwareModule
|
||||
*/
|
||||
@Override
|
||||
public SoftwareModule getSoftwareModule() {
|
||||
return softwareModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareModule
|
||||
* the softwareModule to set
|
||||
*/
|
||||
public final void setSoftwareModule(final SoftwareModule softwareModule) {
|
||||
this.softwareModule = softwareModule;
|
||||
this.softwareModule.addArtifact(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the externalArtifactProvider
|
||||
*/
|
||||
public ExternalArtifactProvider getExternalArtifactProvider() {
|
||||
return externalArtifactProvider;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return new StringBuilder().append(externalArtifactProvider.getBasePath()).append(urlSuffix).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the urlSuffix
|
||||
*/
|
||||
public String getUrlSuffix() {
|
||||
return urlSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param externalArtifactProvider
|
||||
* the externalArtifactProvider to set
|
||||
*/
|
||||
public void setExternalArtifactProvider(final ExternalArtifactProvider externalArtifactProvider) {
|
||||
this.externalArtifactProvider = externalArtifactProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param urlSuffix
|
||||
* the urlSuffix to set
|
||||
*/
|
||||
public void setUrlSuffix(final String urlSuffix) {
|
||||
this.urlSuffix = urlSuffix;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + this.getClass().getName().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof ExternalArtifact)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* External repositories for artifact storage. The SP server provides URLs for
|
||||
* the targets to download rom these external ressources but does not access
|
||||
* thenm itself.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Table(name = "sp_external_provider", indexes = {
|
||||
@Index(name = "sp_idx_external_provider_prim", columnList = "tenant,id") })
|
||||
@Entity
|
||||
public class ExternalArtifactProvider extends NamedEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "base_url", length = 512, nullable = false)
|
||||
private String basePath;
|
||||
|
||||
@Column(name = "default_url_suffix", length = 512, nullable = true)
|
||||
private String defaultSuffix;
|
||||
|
||||
/**
|
||||
* Constructs {@link ExternalArtifactProvider} based on given properties.
|
||||
*
|
||||
* @param name
|
||||
* of the provided
|
||||
* @param description
|
||||
* which is optional
|
||||
* @param baseURL
|
||||
* of all {@link ExternalArtifact}s of the provider
|
||||
* @param defaultUrlSuffix
|
||||
* that is used if {@link ExternalArtifact#getUrlSuffix()} is
|
||||
* empty.
|
||||
*/
|
||||
public ExternalArtifactProvider(final String name, final String description, final String baseURL,
|
||||
final String defaultUrlSuffix) {
|
||||
super(name, description);
|
||||
basePath = baseURL;
|
||||
defaultSuffix = defaultUrlSuffix;
|
||||
}
|
||||
|
||||
ExternalArtifactProvider() {
|
||||
super();
|
||||
defaultSuffix = "";
|
||||
basePath = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the basePath
|
||||
*/
|
||||
public String getBasePath() {
|
||||
return basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the defaultSuffix
|
||||
*/
|
||||
public String getDefaultSuffix() {
|
||||
return defaultSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param basePath
|
||||
* the basePath to set
|
||||
*/
|
||||
public void setBasePath(final String basePath) {
|
||||
this.basePath = basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param defaultSuffix
|
||||
* the defaultSuffix to set
|
||||
*/
|
||||
public void setDefaultSuffix(final String defaultSuffix) {
|
||||
this.defaultSuffix = defaultSuffix;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + this.getClass().getName().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof ExternalArtifactProvider)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import com.mongodb.gridfs.GridFS;
|
||||
import com.mongodb.gridfs.GridFSFile;
|
||||
|
||||
/**
|
||||
* Tenant specific locally stored artifact representation that is used by
|
||||
* {@link SoftwareModule} . It contains all information that is provided by the
|
||||
* user while all SP server generated information related to the artifact (hash,
|
||||
* length) is stored directly with the binary itself.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Table(name = "sp_artifact", indexes = { @Index(name = "sp_idx_artifact_01", columnList = "tenant,software_module"),
|
||||
@Index(name = "sp_idx_artifact_prim", columnList = "tenant,id") })
|
||||
@Entity
|
||||
public class LocalArtifact extends Artifact {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "gridfs_file_name", length = 40)
|
||||
private String gridFsFileName;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "provided_file_name", length = 256)
|
||||
private String filename;
|
||||
|
||||
@ManyToOne(optional = false, cascade = { CascadeType.PERSIST })
|
||||
@JoinColumn(name = "software_module", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_assigned_sm") )
|
||||
private SoftwareModule softwareModule;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public LocalArtifact() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs artifact.
|
||||
*
|
||||
* @param gridFsFileName
|
||||
* that is the link to the {@link GridFS} entity.
|
||||
* @param filename
|
||||
* that is used by {@link GridFSFile} store.
|
||||
* @param softwareModule
|
||||
* of this artifact
|
||||
*/
|
||||
public LocalArtifact(@NotNull final String gridFsFileName, @NotNull final String filename,
|
||||
final SoftwareModule softwareModule) {
|
||||
setSoftwareModule(softwareModule);
|
||||
this.gridFsFileName = gridFsFileName;
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + this.getClass().getName().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof LocalArtifact)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the softwareModule
|
||||
*/
|
||||
@Override
|
||||
public SoftwareModule getSoftwareModule() {
|
||||
return softwareModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareModule
|
||||
* the softwareModule to set
|
||||
*/
|
||||
public final void setSoftwareModule(final SoftwareModule softwareModule) {
|
||||
this.softwareModule = softwareModule;
|
||||
this.softwareModule.addArtifact(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the gridFsFileName
|
||||
*/
|
||||
public String getGridFsFileName() {
|
||||
return gridFsFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the filename
|
||||
*/
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
* {@link BaseEntity} extension for all entities that are named in addition to
|
||||
* their technical ID.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class NamedEntity extends BaseEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "name", nullable = false, length = 64)
|
||||
private String name;
|
||||
|
||||
@Column(name = "description", nullable = true, length = 512)
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public NamedEntity() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param name
|
||||
* of the {@link NamedEntity}
|
||||
* @param description
|
||||
* of the {@link NamedEntity}
|
||||
*/
|
||||
public NamedEntity(final String name, final String description) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
* Extension for {@link NamedEntity} that are versioned.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class NamedVersionedEntity extends NamedEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "version", nullable = false, length = 64)
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* parameterized constructor.
|
||||
*
|
||||
* @param name
|
||||
* of the entity
|
||||
* @param version
|
||||
* of the entity
|
||||
* @param description
|
||||
*/
|
||||
public NamedVersionedEntity(final String name, final String version, final String description) {
|
||||
super(name, description);
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
NamedVersionedEntity() {
|
||||
super();
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(final String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedAttributeNode;
|
||||
import javax.persistence.NamedEntityGraph;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.eclipse.persistence.annotations.CascadeOnDelete;
|
||||
|
||||
/**
|
||||
* Base Software Module that is supported by OS level provisioning mechanism on
|
||||
* the edge controller, e.g. OS, JVM, AgentHub
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "sp_base_software_module", uniqueConstraints = @UniqueConstraint(columnNames = { "module_type", "name",
|
||||
"version", "tenant" }, name = "uk_base_sw_mod") , indexes = {
|
||||
@Index(name = "sp_idx_base_sw_module_01", columnList = "tenant,deleted,name,version"),
|
||||
@Index(name = "sp_idx_base_sw_module_02", columnList = "tenant,deleted,module_type"),
|
||||
@Index(name = "sp_idx_base_sw_module_prim", columnList = "tenant,id") })
|
||||
@NamedEntityGraph(name = "SoftwareModule.artifacts", attributeNodes = { @NamedAttributeNode("artifacts") })
|
||||
public class SoftwareModule extends NamedVersionedEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "module_type", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_module_type") )
|
||||
private SoftwareModuleType type;
|
||||
|
||||
@ManyToMany(mappedBy = "modules", targetEntity = DistributionSet.class, fetch = FetchType.LAZY)
|
||||
private final List<DistributionSet> assignedTo = new ArrayList<DistributionSet>();
|
||||
|
||||
@Column(name = "deleted")
|
||||
private boolean deleted = false;
|
||||
|
||||
@Column(name = "vendor", nullable = true, length = 256)
|
||||
private String vendor;
|
||||
|
||||
@OneToMany(mappedBy = "softwareModule", cascade = { CascadeType.ALL }, targetEntity = LocalArtifact.class)
|
||||
private List<LocalArtifact> artifacts;
|
||||
|
||||
@OneToMany(mappedBy = "softwareModule", cascade = { CascadeType.ALL }, targetEntity = ExternalArtifact.class)
|
||||
private List<ExternalArtifact> externalArtifacts;
|
||||
|
||||
@CascadeOnDelete
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE })
|
||||
@JoinColumn(name = "sw_id", insertable = false, updatable = false)
|
||||
private final List<SoftwareModuleMetadata> metadata = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public SoftwareModule() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* parameterized constructor.
|
||||
*
|
||||
* @param type
|
||||
* of the {@link SoftwareModule}
|
||||
* @param name
|
||||
* abstract name of the {@link SoftwareModule}
|
||||
* @param version
|
||||
* of the {@link SoftwareModule}
|
||||
* @param description
|
||||
* of the {@link SoftwareModule}
|
||||
* @param vendor
|
||||
* of the {@link SoftwareModule}
|
||||
*/
|
||||
public SoftwareModule(final SoftwareModuleType type, final String name, final String version,
|
||||
final String description, final String vendor) {
|
||||
super(name, version, description);
|
||||
this.vendor = vendor;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param artifact
|
||||
* is added to the assigned {@link Artifact}s.
|
||||
*/
|
||||
public void addArtifact(final LocalArtifact artifact) {
|
||||
if (null == artifacts) {
|
||||
artifacts = new ArrayList<>(4);
|
||||
}
|
||||
|
||||
if (!artifacts.contains(artifact)) {
|
||||
artifacts.add(artifact);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param artifact
|
||||
* is added to the assigned {@link Artifact}s.
|
||||
*/
|
||||
public void addArtifact(final ExternalArtifact artifact) {
|
||||
if (null == externalArtifacts) {
|
||||
externalArtifacts = new ArrayList<>(4);
|
||||
}
|
||||
|
||||
if (!externalArtifacts.contains(artifact)) {
|
||||
externalArtifacts.add(artifact);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param artifactId
|
||||
* to look for
|
||||
* @return found {@link Artifact}
|
||||
*/
|
||||
public Optional<LocalArtifact> getLocalArtifact(final Long artifactId) {
|
||||
if (null == artifacts) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return artifacts.stream().filter(artifact -> artifact.getId().equals(artifactId)).findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileName
|
||||
* to look for
|
||||
* @return found {@link Artifact}
|
||||
*/
|
||||
public Optional<LocalArtifact> getLocalArtifactByFilename(final String fileName) {
|
||||
if (null == artifacts) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return artifacts.stream().filter(artifact -> artifact.getFilename().equalsIgnoreCase(fileName.trim()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the artifacts
|
||||
*/
|
||||
public List<Artifact> getArtifacts() {
|
||||
final List<Artifact> result = new ArrayList<Artifact>();
|
||||
result.addAll(artifacts);
|
||||
result.addAll(externalArtifacts);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return local artifacts only
|
||||
*/
|
||||
public List<LocalArtifact> getLocalArtifacts() {
|
||||
if (artifacts == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return artifacts;
|
||||
}
|
||||
|
||||
public String getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param artifact
|
||||
* is removed from the assigned {@link LocalArtifact}s.
|
||||
*/
|
||||
public void removeArtifact(final LocalArtifact artifact) {
|
||||
if (null != artifacts) {
|
||||
artifacts.remove(artifact);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param artifact
|
||||
* is removed from the assigned {@link ExternalArtifact}s.
|
||||
*/
|
||||
public void removeArtifact(final ExternalArtifact artifact) {
|
||||
if (null != externalArtifacts) {
|
||||
externalArtifacts.remove(artifact);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVendor(final String vendor) {
|
||||
this.vendor = vendor;
|
||||
}
|
||||
|
||||
public SoftwareModuleType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deleted
|
||||
*/
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param deleted
|
||||
* the deleted to set
|
||||
*/
|
||||
public void setDeleted(final boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public void setType(final SoftwareModuleType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the metadata
|
||||
*/
|
||||
public List<SoftwareModuleMetadata> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SoftwareModule [type=" + type + ", deleted=" + deleted + ", getVersion()=" + getVersion()
|
||||
+ ", getOptLockRevision()=" + getOptLockRevision() + ", getId()=" + getId() + "]";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + this.getClass().getName().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof SoftwareModule)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the assignedTo
|
||||
*/
|
||||
public List<DistributionSet> getAssignedTo() {
|
||||
return assignedTo;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* To hold software module name and Id.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class SoftwareModuleIdName implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6317413180936148514L;
|
||||
|
||||
private final Long id;
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* if the {@link SoftwareModule}
|
||||
* @param name
|
||||
* of the {@link SoftwareModule}
|
||||
*/
|
||||
public SoftwareModuleIdName(final Long id, final String name) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {// NOSONAR - as this is generated
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (id == null ? 0 : id.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {// NOSONAR - as this is generated
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final SoftwareModuleIdName other = (SoftwareModuleIdName) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* Metadata for {@link SoftwareModule}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@IdClass(SwMetadataCompositeKey.class)
|
||||
@Entity
|
||||
@Table(name = "sp_sw_metadata")
|
||||
public class SoftwareModuleMetadata implements Serializable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@Column(name = "meta_key", length = 128)
|
||||
private String key;
|
||||
|
||||
@Column(name = "meta_value", length = 4000)
|
||||
private String value;
|
||||
|
||||
@Id
|
||||
@ManyToOne(targetEntity = SoftwareModule.class, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "sw_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_metadata_sw") )
|
||||
private SoftwareModule softwareModule;
|
||||
|
||||
public SoftwareModuleMetadata() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard constructor.
|
||||
*
|
||||
* @param key
|
||||
* of the metadata element
|
||||
* @param softwareModule
|
||||
* @param value
|
||||
* of the metadata element
|
||||
*/
|
||||
public SoftwareModuleMetadata(final String key, final SoftwareModule softwareModule, final String value) {
|
||||
this.key = key;
|
||||
this.softwareModule = softwareModule;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public SwMetadataCompositeKey getId() {
|
||||
return new SwMetadataCompositeKey(softwareModule, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* the value to set
|
||||
*/
|
||||
public void setValue(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the softwareModule
|
||||
*/
|
||||
public SoftwareModule getSoftwareModule() {
|
||||
return softwareModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareModule
|
||||
* the softwareModule to set
|
||||
*/
|
||||
public void setSoftwareModule(final SoftwareModule softwareModule) {
|
||||
this.softwareModule = softwareModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the key
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* the key to set
|
||||
*/
|
||||
public void setKey(final String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user