forked from community/device-mgt-core
Implement scheduled application install/uninstall feature See merge request entgra/carbon-device-mgt!250feature/appm-store/pbac
commit
c91e1c43e7
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.application.mgt.common;
|
||||||
|
|
||||||
|
public enum ExecutionStatus {
|
||||||
|
PENDING, EXECUTED, FAILED
|
||||||
|
}
|
2
components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/SubsciptionType.java → components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/SubscriptionType.java
2
components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/SubsciptionType.java → components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/SubscriptionType.java
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.application.mgt.common.dto;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.ExecutionStatus;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.SubscriptionType;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a DTO for AP_SCHEDULED_SUBSCRIPTION table
|
||||||
|
*/
|
||||||
|
public class ScheduledSubscriptionDTO {
|
||||||
|
/**
|
||||||
|
* Generated ID of the subscription.
|
||||||
|
*/
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the task which is related to the subscription.
|
||||||
|
*
|
||||||
|
* Task name is a generated field and in the following pattern:
|
||||||
|
* {@code <SUBSCRIPTION-TYPE>_<ACTION>_<HASH-VALUE>}
|
||||||
|
* {@code SUBSCRIPTION-TYPE} - {@see {@linkplain SubscriptionType}}
|
||||||
|
* {@code ACTION} - {@see {@linkplain org.wso2.carbon.device.application.mgt.common.SubAction}
|
||||||
|
* {@code HASH-VALUE} - this is a hash value of the combination of application uuid and the subscriber list.
|
||||||
|
*
|
||||||
|
* Example: {@code DEVICE_INSTALL_e593e00e8ef55efc764295b6aa9ad56b}
|
||||||
|
*/
|
||||||
|
private String taskName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UUID of the application release which is subscribed to.
|
||||||
|
* {@see {@link org.wso2.carbon.device.application.mgt.common.response.ApplicationRelease}}
|
||||||
|
*/
|
||||||
|
private String applicationUUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of subscribers for the application release. The type of the list depends on the subscription type.
|
||||||
|
* {@see {@link SubscriptionType}}. If the subscription type is {@code SubscriptionType.DEVICE} the type will be
|
||||||
|
* {@link org.wso2.carbon.device.mgt.common.DeviceIdentifier} and if not the type will be {@link String}.
|
||||||
|
*/
|
||||||
|
private List<?> subscriberList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status of the subscription. {@see {@link ExecutionStatus}}
|
||||||
|
*/
|
||||||
|
private ExecutionStatus status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scheduled time of subscription.
|
||||||
|
*/
|
||||||
|
private LocalDateTime scheduledAt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Username of the scheduler.
|
||||||
|
*/
|
||||||
|
private String scheduledBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the subscription is marked as deleted or not.
|
||||||
|
* {@code true} means that the related task is removed from the {@link org.wso2.carbon.ntask.core.TaskManager}.
|
||||||
|
*/
|
||||||
|
private boolean deleted;
|
||||||
|
|
||||||
|
public ScheduledSubscriptionDTO() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledSubscriptionDTO(String taskName, String applicationUUID, LocalDateTime scheduledAt,
|
||||||
|
List<?> subscriberList, String scheduledBy) {
|
||||||
|
this.taskName = taskName;
|
||||||
|
this.applicationUUID = applicationUUID;
|
||||||
|
this.scheduledAt = scheduledAt;
|
||||||
|
this.subscriberList = subscriberList;
|
||||||
|
this.scheduledBy = scheduledBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTaskName() {
|
||||||
|
return taskName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTaskName(String taskName) {
|
||||||
|
this.taskName = taskName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApplicationUUID() {
|
||||||
|
return applicationUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApplicationUUID(String applicationUUID) {
|
||||||
|
this.applicationUUID = applicationUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<?> getSubscriberList() {
|
||||||
|
return subscriberList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubscriberList(List<?> subscriberList) {
|
||||||
|
this.subscriberList = subscriberList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecutionStatus getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(ExecutionStatus status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getScheduledAt() {
|
||||||
|
return scheduledAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScheduledAt(LocalDateTime scheduledAt) {
|
||||||
|
this.scheduledAt = scheduledAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getScheduledBy() {
|
||||||
|
return scheduledBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScheduledBy(String scheduledBy) {
|
||||||
|
this.scheduledBy = scheduledBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the string representation of the subscriber list.
|
||||||
|
*/
|
||||||
|
public String getSubscribersString() {
|
||||||
|
if (this.taskName.startsWith(SubscriptionType.DEVICE.toString())) {
|
||||||
|
return new Gson().toJson(this.subscriberList);
|
||||||
|
} else {
|
||||||
|
return this.subscriberList.stream().map(String.class::cast).collect(Collectors.joining(","));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDeleted() {
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeleted(boolean deleted) {
|
||||||
|
this.deleted = deleted;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.application.mgt.common.exception;
|
||||||
|
|
||||||
|
public class SubscriptionManagementException extends Exception {
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public SubscriptionManagementException(String message, Throwable throwable) {
|
||||||
|
super(message, throwable);
|
||||||
|
setMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubscriptionManagementException(String message) {
|
||||||
|
super(message);
|
||||||
|
setMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubscriptionManagementException() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.application.mgt.core.exception;
|
||||||
|
|
||||||
|
public class ApplicationOperationTaskException extends Exception {
|
||||||
|
|
||||||
|
public ApplicationOperationTaskException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApplicationOperationTaskException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.application.mgt.core.task;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.exception.SubscriptionManagementException;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager;
|
||||||
|
import org.wso2.carbon.device.application.mgt.core.impl.SubscriptionManagerImpl;
|
||||||
|
import org.wso2.carbon.ntask.core.Task;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ScheduledAppSubscriptionCleanupTask implements Task {
|
||||||
|
private static Log log = LogFactory.getLog(ScheduledAppSubscriptionCleanupTask.class);
|
||||||
|
private SubscriptionManager subscriptionManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProperties(Map<String, String> properties) {
|
||||||
|
//no properties required
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
if (this.subscriptionManager == null) {
|
||||||
|
this.subscriptionManager = new SubscriptionManagerImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
try {
|
||||||
|
subscriptionManager.cleanScheduledSubscriptions();
|
||||||
|
} catch (SubscriptionManagementException e) {
|
||||||
|
log.error("Error occurred while cleaning up tasks.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.application.mgt.core.task;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.ExecutionStatus;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.SubscriptionType;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.dto.ScheduledSubscriptionDTO;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.exception.SubscriptionManagementException;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager;
|
||||||
|
import org.wso2.carbon.device.application.mgt.core.impl.SubscriptionManagerImpl;
|
||||||
|
import org.wso2.carbon.device.application.mgt.core.util.Constants;
|
||||||
|
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
||||||
|
import org.wso2.carbon.ntask.core.Task;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ScheduledAppSubscriptionTask implements Task {
|
||||||
|
private static Log log = LogFactory.getLog(ScheduledAppSubscriptionTask.class);
|
||||||
|
private SubscriptionManager subscriptionManager;
|
||||||
|
private String subscribers;
|
||||||
|
private String subscriptionType;
|
||||||
|
private String application;
|
||||||
|
private String action;
|
||||||
|
private String subscriber;
|
||||||
|
private String tenantDomain;
|
||||||
|
private String taskName;
|
||||||
|
private int tenantId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProperties(Map<String, String> map) {
|
||||||
|
this.subscribers = map.get(Constants.SUBSCRIBERS);
|
||||||
|
this.subscriptionType = map.get(Constants.SUB_TYPE);
|
||||||
|
this.application = map.get(Constants.APP_UUID);
|
||||||
|
this.action = map.get(Constants.ACTION);
|
||||||
|
this.subscriber = map.get(Constants.SUBSCRIBER);
|
||||||
|
this.tenantDomain = map.get(Constants.TENANT_DOMAIN);
|
||||||
|
this.tenantId = Integer.parseInt(map.get(Constants.TENANT_ID));
|
||||||
|
this.taskName = map.get(Constants.TASK_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
if (this.subscriptionManager == null) {
|
||||||
|
this.subscriptionManager = new SubscriptionManagerImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
try {
|
||||||
|
ScheduledSubscriptionDTO subscriptionDTO = subscriptionManager.getPendingScheduledSubscription(
|
||||||
|
this.taskName);
|
||||||
|
if (subscriptionDTO == null) {
|
||||||
|
log.error("Unable to execute the task. Task entry for [" + this.taskName + "] cannot be retrieved " +
|
||||||
|
"from the database.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(this.subscribers)) {
|
||||||
|
PrivilegedCarbonContext.startTenantFlow();
|
||||||
|
PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
|
||||||
|
carbonContext.setTenantDomain(this.tenantDomain);
|
||||||
|
carbonContext.setTenantId(this.tenantId);
|
||||||
|
carbonContext.setUsername(this.subscriber);
|
||||||
|
|
||||||
|
if (this.subscriptionType.equals(SubscriptionType.DEVICE.toString())) {
|
||||||
|
List<DeviceIdentifier> deviceIdentifiers = new Gson().fromJson(this.subscribers,
|
||||||
|
new TypeToken<List<DeviceIdentifier>>() {
|
||||||
|
}.getType());
|
||||||
|
try {
|
||||||
|
subscriptionManager.performBulkAppOperation(this.application, deviceIdentifiers,
|
||||||
|
this.subscriptionType, this.action);
|
||||||
|
subscriptionDTO.setStatus(ExecutionStatus.EXECUTED);
|
||||||
|
} catch (ApplicationManagementException e) {
|
||||||
|
log.error(
|
||||||
|
"Error occurred while " + this.action + "ing application " + this.application
|
||||||
|
+ "to/from the following devices: " + this.subscribers, e);
|
||||||
|
subscriptionDTO.setStatus(ExecutionStatus.FAILED);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
List<String> subscriberList = Pattern.compile(",").splitAsStream(this.subscribers).collect(
|
||||||
|
Collectors.toList());
|
||||||
|
try {
|
||||||
|
subscriptionManager.performBulkAppOperation(this.application, subscriberList,
|
||||||
|
this.subscriptionType, this.action);
|
||||||
|
subscriptionDTO.setStatus(ExecutionStatus.EXECUTED);
|
||||||
|
} catch (ApplicationManagementException e) {
|
||||||
|
log.error(
|
||||||
|
"Error occurred while " + this.action + "ing application " + this.application
|
||||||
|
+ "to/from the following " + this.subscriptionType + "s: " + this.subscribers, e);
|
||||||
|
subscriptionDTO.setStatus(ExecutionStatus.FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn(
|
||||||
|
"Subscriber list is empty. Therefore skipping scheduled task to " + this.action + "application "
|
||||||
|
+ this.application);
|
||||||
|
subscriptionDTO.setStatus(ExecutionStatus.FAILED);
|
||||||
|
}
|
||||||
|
subscriptionManager.updateScheduledSubscriptionStatus(subscriptionDTO.getId(), subscriptionDTO.getStatus());
|
||||||
|
} catch (SubscriptionManagementException e) {
|
||||||
|
log.error("Error occurred while executing the task: " + this.taskName, e);
|
||||||
|
} finally {
|
||||||
|
PrivilegedCarbonContext.endTenantFlow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.application.mgt.core.task;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.quartz.CronExpression;
|
||||||
|
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.SubAction;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.SubscriptionType;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.dto.ScheduledSubscriptionDTO;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.exception.SubscriptionManagementException;
|
||||||
|
import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager;
|
||||||
|
import org.wso2.carbon.device.application.mgt.core.exception.ApplicationOperationTaskException;
|
||||||
|
import org.wso2.carbon.device.application.mgt.core.impl.SubscriptionManagerImpl;
|
||||||
|
import org.wso2.carbon.device.application.mgt.core.internal.DataHolder;
|
||||||
|
import org.wso2.carbon.device.application.mgt.core.util.Constants;
|
||||||
|
import org.wso2.carbon.ntask.common.TaskException;
|
||||||
|
import org.wso2.carbon.ntask.core.TaskInfo;
|
||||||
|
import org.wso2.carbon.ntask.core.TaskManager;
|
||||||
|
import org.wso2.carbon.ntask.core.service.TaskService;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.TextStyle;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ScheduledAppSubscriptionTaskManager {
|
||||||
|
private static Log log = LogFactory.getLog(ScheduledAppSubscriptionTaskManager.class);
|
||||||
|
private static final String SCHEDULED_APP_SUBSCRIPTION_TASK_TYPE = "SCHEDULED_APP_SUBSCRIPTION_TASK_TYPE";
|
||||||
|
private static final String NAME_SEPARATOR = "_";
|
||||||
|
private SubscriptionManager subscriptionManager;
|
||||||
|
|
||||||
|
public ScheduledAppSubscriptionTaskManager() {
|
||||||
|
this.subscriptionManager = new SubscriptionManagerImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule a task to install/uninstall application for a list of subscribers
|
||||||
|
*
|
||||||
|
* @param applicationUUID UUID of the application to install
|
||||||
|
* @param subscribers list of subscribers. This list can be of
|
||||||
|
* either {@link org.wso2.carbon.device.mgt.common.DeviceIdentifier} if {@param subType} is
|
||||||
|
* equal to DEVICE or {@link String} if {@param subType} is USER, ROLE or GROUP
|
||||||
|
* @param subscriptionType subscription type. E.g. <code>DEVICE, USER, ROLE, GROUP</code>
|
||||||
|
* {@see {@link org.wso2.carbon.device.application.mgt.common.SubscriptionType}}
|
||||||
|
* @param action action subscription action. E.g. {@code INSTALL/UNINSTALL}
|
||||||
|
* {@see {@link org.wso2.carbon.device.application.mgt.common.SubAction}}
|
||||||
|
* @param timestamp timestamp to schedule the application subscription
|
||||||
|
* @throws ApplicationOperationTaskException if error occurred while scheduling the subscription
|
||||||
|
*/
|
||||||
|
public void scheduleAppSubscriptionTask(String applicationUUID, List<?> subscribers,
|
||||||
|
SubscriptionType subscriptionType, SubAction action, LocalDateTime timestamp)
|
||||||
|
throws ApplicationOperationTaskException {
|
||||||
|
String space = " ";
|
||||||
|
String cronExpression =
|
||||||
|
String.valueOf(timestamp.getSecond()) + space + timestamp.getMinute() + space + timestamp.getHour()
|
||||||
|
+ space + timestamp.getDayOfMonth() + space + timestamp.getMonth().getDisplayName(TextStyle.SHORT,
|
||||||
|
Locale.getDefault()).toUpperCase() + " ? " + timestamp.getYear();
|
||||||
|
|
||||||
|
if (!CronExpression.isValidExpression(cronExpression)) {
|
||||||
|
String msg = "The cron expression [" + cronExpression + "] generated by the" + " timestamp [" + timestamp
|
||||||
|
.toString() + "] is invalid";
|
||||||
|
log.error(msg);
|
||||||
|
throw new ApplicationOperationTaskException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
|
||||||
|
TaskService taskService = initializeTaskType();
|
||||||
|
|
||||||
|
TaskManager taskManager = taskService.getTaskManager(SCHEDULED_APP_SUBSCRIPTION_TASK_TYPE);
|
||||||
|
TaskInfo.TriggerInfo triggerInfo = new TaskInfo.TriggerInfo();
|
||||||
|
triggerInfo.setCronExpression(cronExpression);
|
||||||
|
triggerInfo.setRepeatCount(0);
|
||||||
|
|
||||||
|
Map<String, String> taskProperties = new HashMap<>();
|
||||||
|
taskProperties.put(Constants.SUB_TYPE, subscriptionType.toString());
|
||||||
|
taskProperties.put(Constants.ACTION, action.toString());
|
||||||
|
taskProperties.put(Constants.APP_UUID, applicationUUID);
|
||||||
|
taskProperties.put(Constants.TENANT_DOMAIN, carbonContext.getTenantDomain(true));
|
||||||
|
taskProperties.put(Constants.SUBSCRIBER, carbonContext.getUsername());
|
||||||
|
|
||||||
|
String subscribersString;
|
||||||
|
if (SubscriptionType.DEVICE.equals(subscriptionType)) {
|
||||||
|
subscribersString = new Gson().toJson(subscribers);
|
||||||
|
taskProperties.put(Constants.SUBSCRIBERS, subscribersString);
|
||||||
|
} else {
|
||||||
|
subscribersString = subscribers.stream().map(String.class::cast).collect(Collectors.joining(","));
|
||||||
|
taskProperties.put(Constants.SUBSCRIBERS, subscribersString);
|
||||||
|
}
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Scheduling a task to " + action.toString() + " application: " + applicationUUID +
|
||||||
|
" to/from the following " + subscriptionType.toString() + "S [" + subscribersString + "] at: "
|
||||||
|
+ timestamp);
|
||||||
|
}
|
||||||
|
String taskName = subscriptionType.toString() + NAME_SEPARATOR + action.toString() + NAME_SEPARATOR
|
||||||
|
+ DigestUtils.md5Hex(applicationUUID + NAME_SEPARATOR + subscribersString);
|
||||||
|
taskProperties.put(Constants.TASK_NAME, taskName);
|
||||||
|
TaskInfo taskInfo = new TaskInfo(taskName, ScheduledAppSubscriptionTask.class.getName(),
|
||||||
|
taskProperties, triggerInfo);
|
||||||
|
|
||||||
|
ScheduledSubscriptionDTO subscriptionDTO = new ScheduledSubscriptionDTO(taskName, applicationUUID,
|
||||||
|
timestamp, subscribers, carbonContext.getUsername());
|
||||||
|
subscriptionManager.createScheduledSubscription(subscriptionDTO);
|
||||||
|
|
||||||
|
taskManager.registerTask(taskInfo);
|
||||||
|
if (!taskManager.isTaskScheduled(taskName)) {
|
||||||
|
taskManager.scheduleTask(taskName);
|
||||||
|
} else {
|
||||||
|
taskManager.rescheduleTask(taskName);
|
||||||
|
}
|
||||||
|
} catch (TaskException e) {
|
||||||
|
String msg = "Error occurred while scheduling a task to " + action.toString() + " application: "
|
||||||
|
+ applicationUUID + " to/from given " + subscriptionType.toString() + "S";
|
||||||
|
log.error(msg, e);
|
||||||
|
throw new ApplicationOperationTaskException(msg, e);
|
||||||
|
} catch (SubscriptionManagementException e) {
|
||||||
|
String msg = "Error occurred while writing the subscription to database";
|
||||||
|
log.error(msg, e);
|
||||||
|
throw new ApplicationOperationTaskException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules a task to clean up the scheduled tasks from {@link org.wso2.carbon.ntask.core.TaskRepository}
|
||||||
|
*/
|
||||||
|
public void scheduleCleanupTask() {
|
||||||
|
try {
|
||||||
|
TaskService taskService = initializeTaskType();
|
||||||
|
TaskManager taskManager = taskService.getTaskManager(SCHEDULED_APP_SUBSCRIPTION_TASK_TYPE);
|
||||||
|
|
||||||
|
TaskInfo.TriggerInfo triggerInfo = new TaskInfo.TriggerInfo();
|
||||||
|
triggerInfo.setCronExpression("0 0 0/24 ? * * *");
|
||||||
|
|
||||||
|
String taskName = "SCHEDULED_APP_SUBSCRIPTION_CLEANUP_TASK";
|
||||||
|
TaskInfo taskInfo = new TaskInfo(taskName, ScheduledAppSubscriptionCleanupTask.class.getName(), null,
|
||||||
|
triggerInfo);
|
||||||
|
|
||||||
|
taskManager.registerTask(taskInfo);
|
||||||
|
if (!taskManager.isTaskScheduled(taskName)) {
|
||||||
|
taskManager.scheduleTask(taskName);
|
||||||
|
} else {
|
||||||
|
taskManager.rescheduleTask(taskName);
|
||||||
|
}
|
||||||
|
} catch (TaskException e) {
|
||||||
|
log.error("Error occurred while scheduling a cleanup task.");
|
||||||
|
} catch (ApplicationOperationTaskException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize task type.
|
||||||
|
*
|
||||||
|
* @return {@link TaskService}
|
||||||
|
* @throws TaskException if error occurred while initializing task type
|
||||||
|
* @throws ApplicationOperationTaskException if unable to load {@link TaskService}
|
||||||
|
*/
|
||||||
|
private TaskService initializeTaskType() throws TaskException, ApplicationOperationTaskException {
|
||||||
|
TaskService taskService = DataHolder.getInstance().getTaskService();
|
||||||
|
if (taskService == null) {
|
||||||
|
String msg = "Unable to load TaskService, hence unable to schedule the task.";
|
||||||
|
log.error(msg);
|
||||||
|
throw new ApplicationOperationTaskException(msg);
|
||||||
|
}
|
||||||
|
if (!taskService.getRegisteredTaskTypes().contains(SCHEDULED_APP_SUBSCRIPTION_TASK_TYPE)) {
|
||||||
|
try {
|
||||||
|
List<ScheduledSubscriptionDTO> removedTaskList = subscriptionManager.cleanScheduledSubscriptions();
|
||||||
|
removeScheduledSubscriptions(taskService, removedTaskList);
|
||||||
|
} catch (SubscriptionManagementException e) {
|
||||||
|
log.error("Error occurred while retrieving tasks to cleanup", e);
|
||||||
|
}
|
||||||
|
taskService.registerTaskType(SCHEDULED_APP_SUBSCRIPTION_TASK_TYPE);
|
||||||
|
}
|
||||||
|
return taskService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up already scheduled subscriptions.
|
||||||
|
*
|
||||||
|
* @param taskList list of {@link ScheduledSubscriptionDTO}s to remove
|
||||||
|
*/
|
||||||
|
private void removeScheduledSubscriptions(TaskService taskService, List<ScheduledSubscriptionDTO> taskList) {
|
||||||
|
try {
|
||||||
|
TaskManager taskManager = taskService.getTaskManager(SCHEDULED_APP_SUBSCRIPTION_TASK_TYPE);
|
||||||
|
taskManager.getAllTasks().forEach(
|
||||||
|
task -> taskList.stream().filter(t -> t.getTaskName().equals(task.getName())).forEach(t -> {
|
||||||
|
try {
|
||||||
|
taskManager.deleteTask(t.getTaskName());
|
||||||
|
} catch (TaskException e) {
|
||||||
|
log.error("Error occurred while removing the task: " + t.getTaskName(), e);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} catch (TaskException e) {
|
||||||
|
log.error("Error occurred while removing tasks", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue