forked from community/device-mgt-core
commit
7ec652a910
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.jaxrs.beans;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ApiModel(value = "RemoteSessionInfo", description = "Template of the remote session")
|
||||||
|
public class RemoteSessionInfo {
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "Server Url", value = "Url of the remote session server.", required = true)
|
||||||
|
private String serverUrl;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "isEnabled", value = "Is remote session functionality enabled", required = true)
|
||||||
|
private Boolean isEnabled;
|
||||||
|
|
||||||
|
public String getServerUrl() {
|
||||||
|
return serverUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerUrl(String serverUrl) {
|
||||||
|
this.serverUrl = serverUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getEnabled() {
|
||||||
|
return isEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(Boolean enabled) {
|
||||||
|
isEnabled = enabled;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.jaxrs.service.api;
|
||||||
|
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
|
import io.swagger.annotations.ApiResponse;
|
||||||
|
import io.swagger.annotations.ApiResponses;
|
||||||
|
import io.swagger.annotations.Extension;
|
||||||
|
import io.swagger.annotations.ExtensionProperty;
|
||||||
|
import io.swagger.annotations.Info;
|
||||||
|
import io.swagger.annotations.ResponseHeader;
|
||||||
|
import io.swagger.annotations.SwaggerDefinition;
|
||||||
|
import io.swagger.annotations.Tag;
|
||||||
|
import org.wso2.carbon.apimgt.annotations.api.Scope;
|
||||||
|
import org.wso2.carbon.apimgt.annotations.api.Scopes;
|
||||||
|
import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
@SwaggerDefinition(
|
||||||
|
info = @Info(
|
||||||
|
version = "1.0.0",
|
||||||
|
title = "",
|
||||||
|
extensions = {
|
||||||
|
@Extension(properties = {
|
||||||
|
@ExtensionProperty(name = "name", value = "remote_session_services"),
|
||||||
|
@ExtensionProperty(name = "context", value = "/api/device-mgt/v1.0/remote-session-services"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
),
|
||||||
|
tags = {
|
||||||
|
@Tag(name = "device_management", description = "")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@Scopes(
|
||||||
|
scopes = {
|
||||||
|
@Scope(
|
||||||
|
name = "Remote Session Connection",
|
||||||
|
description = "",
|
||||||
|
key = "perm:remote-session-service:connect",
|
||||||
|
permissions = {"/device-mgt/devices/owning-device/remote-session"}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@Path("/remote-session-services")
|
||||||
|
@Api(value = "Remote Session Service",
|
||||||
|
description = "This carries all the resources related to the remote session service functionality.")
|
||||||
|
public interface RemoteSessionService {
|
||||||
|
/**
|
||||||
|
* Retrieve Analytics for the device type
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("connection/{deviceType}/{deviceId}")
|
||||||
|
@ApiOperation(
|
||||||
|
consumes = "application/json",
|
||||||
|
produces = "application/json",
|
||||||
|
httpMethod = "GET",
|
||||||
|
value = "Retrieve Connection Information for the device type",
|
||||||
|
notes = "",
|
||||||
|
response = Response.class,
|
||||||
|
tags = "Remote Session Service Management",
|
||||||
|
extensions = {
|
||||||
|
@Extension(properties = {
|
||||||
|
@ExtensionProperty(name = Constants.SCOPE, value = "perm:remote-session-service:connect")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@ApiResponses(value = {
|
||||||
|
@ApiResponse(
|
||||||
|
code = 200,
|
||||||
|
message = "OK.",
|
||||||
|
response = Response.class,
|
||||||
|
responseHeaders = {
|
||||||
|
@ResponseHeader(
|
||||||
|
name = "Content-Type",
|
||||||
|
description = "The content type of the body"),
|
||||||
|
@ResponseHeader(
|
||||||
|
name = "Last-Modified",
|
||||||
|
description = "Date and time the resource was last modified.\n" +
|
||||||
|
"Used by caches, or in conditional requests."),
|
||||||
|
}),
|
||||||
|
@ApiResponse(
|
||||||
|
code = 400,
|
||||||
|
message = "Bad Request. \n Invalid Device Identifiers found.",
|
||||||
|
response = Response.class),
|
||||||
|
@ApiResponse(
|
||||||
|
code = 401,
|
||||||
|
message = "Unauthorized. \n Unauthorized request."),
|
||||||
|
@ApiResponse(
|
||||||
|
code = 500,
|
||||||
|
message = "Internal Server Error. \n Error on retrieving stats",
|
||||||
|
response = Response.class)
|
||||||
|
})
|
||||||
|
Response getRemoteSessionDeviceConnect(
|
||||||
|
@ApiParam(
|
||||||
|
name = "deviceId",
|
||||||
|
value = "The registered device Id.",
|
||||||
|
required = true)
|
||||||
|
@PathParam("deviceId") String deviceId,
|
||||||
|
@ApiParam(
|
||||||
|
name = "device-type",
|
||||||
|
value = "The device type, such as ios, android or windows.",
|
||||||
|
required = true)
|
||||||
|
@PathParam("deviceType")
|
||||||
|
@Size(max = 45)
|
||||||
|
String deviceType);
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.jaxrs.service.impl;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.DeviceManagementConfig;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.remote.session.RemoteSessionConfiguration;
|
||||||
|
import org.wso2.carbon.device.mgt.jaxrs.beans.RemoteSessionInfo;
|
||||||
|
import org.wso2.carbon.device.mgt.jaxrs.service.api.RemoteSessionService;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The api for
|
||||||
|
*/
|
||||||
|
public class RemoteSessionServiceImpl implements RemoteSessionService {
|
||||||
|
|
||||||
|
private static Log log = LogFactory.getLog(RemoteSessionServiceImpl.class);
|
||||||
|
|
||||||
|
@Path("connect/{deviceType}/{deviceId}")
|
||||||
|
@GET
|
||||||
|
@Consumes("application/json")
|
||||||
|
@Produces("application/json")
|
||||||
|
public Response getRemoteSessionDeviceConnect(@PathParam("deviceId") String deviceId,
|
||||||
|
@PathParam("deviceType") String deviceType) {
|
||||||
|
//First, check whether the remote session is enabled.
|
||||||
|
RemoteSessionInfo sessionInfo = new RemoteSessionInfo();
|
||||||
|
sessionInfo.setEnabled(false);
|
||||||
|
DeviceManagementConfig deviceManagementConfig = DeviceConfigurationManager.getInstance()
|
||||||
|
.getDeviceManagementConfig();
|
||||||
|
if (deviceManagementConfig != null) {
|
||||||
|
RemoteSessionConfiguration remoteSessionConfiguration = deviceManagementConfig.getRemoteSessionConfiguration();
|
||||||
|
if (remoteSessionConfiguration != null) {
|
||||||
|
boolean isEnabled = remoteSessionConfiguration.isEnabled();
|
||||||
|
sessionInfo.setEnabled(isEnabled);
|
||||||
|
if (isEnabled) {
|
||||||
|
sessionInfo.setServerUrl(remoteSessionConfiguration.getRemoteSessionServerUrl());
|
||||||
|
}
|
||||||
|
return Response.ok().entity(sessionInfo).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.ok().entity(sessionInfo).build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.archival;
|
||||||
|
|
||||||
|
|
||||||
|
public class ArchivalException extends Exception {
|
||||||
|
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
public String getErrorMessage() {
|
||||||
|
return errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrorMessage(String errorMessage) {
|
||||||
|
this.errorMessage = errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchivalException(String message) {
|
||||||
|
super(message);
|
||||||
|
setErrorMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchivalException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
setErrorMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ArchivalException(String message, Throwable cause, boolean enableSuppression,
|
||||||
|
boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
setErrorMessage(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.archival;
|
||||||
|
|
||||||
|
public interface ArchivalService {
|
||||||
|
|
||||||
|
void archiveTransactionalRecords() throws ArchivalException;
|
||||||
|
|
||||||
|
void deleteArchivedRecords() throws ArchivalException;
|
||||||
|
}
|
@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.archival;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.wso2.carbon.device.mgt.common.TransactionManagementException;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.dao.*;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ArchivalServiceImpl implements ArchivalService {
|
||||||
|
private static Log log = LogFactory.getLog(ArchivalServiceImpl.class);
|
||||||
|
|
||||||
|
private ArchivalDAO archivalDAO;
|
||||||
|
private DataDeletionDAO dataDeletionDAO;
|
||||||
|
|
||||||
|
private static int ITERATION_COUNT = 10000;
|
||||||
|
|
||||||
|
private String[] NOT_IN_PROGRESS_OPS = new String[]{"COMPLETED", "ERROR", "REPEATED"};
|
||||||
|
private String[] NOT_PENDING_OPS = new String[]{"COMPLETED", "ERROR", "REPEATED", "IN_PROGRESS"};
|
||||||
|
private String[] NOT_PENDING_IN_PROGRESS_OPS = new String[]{"COMPLETED", "ERROR", "REPEATED"};
|
||||||
|
|
||||||
|
public ArchivalServiceImpl() {
|
||||||
|
this.archivalDAO = ArchivalSourceDAOFactory.getDataPurgingDAO();
|
||||||
|
this.dataDeletionDAO = ArchivalDestinationDAOFactory.getDataDeletionDAO();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void archiveTransactionalRecords() throws ArchivalException {
|
||||||
|
try {
|
||||||
|
ArchivalSourceDAOFactory.openConnection();
|
||||||
|
ArchivalDestinationDAOFactory.openConnection();
|
||||||
|
|
||||||
|
List<Integer> allOperations = archivalDAO.getAllOperations();
|
||||||
|
List<Integer> pendingAndIPOperations = archivalDAO.getPendingAndInProgressOperations();
|
||||||
|
|
||||||
|
log.info(allOperations.size() + " All Operations. " + pendingAndIPOperations.size() +
|
||||||
|
" P&IP Operations");
|
||||||
|
//Get the diff of operations
|
||||||
|
Set<Integer> setA = new HashSet<>(allOperations);
|
||||||
|
Set<Integer> setB = new HashSet<>(pendingAndIPOperations);
|
||||||
|
setA.removeAll(setB);
|
||||||
|
|
||||||
|
List<Integer> candidates = new ArrayList<>();
|
||||||
|
candidates.addAll(setA);
|
||||||
|
|
||||||
|
int total = candidates.size();
|
||||||
|
int batches = calculateNumberOfBatches(total);
|
||||||
|
int batchSize = ITERATION_COUNT;
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(total + " Operations ready for archiving. " + batches + " iterations to be done.");
|
||||||
|
}
|
||||||
|
|
||||||
|
beginTransactions();
|
||||||
|
for (int i = 1; i <= batches; i++) {
|
||||||
|
int startIdx = batchSize * (i - 1);
|
||||||
|
int endIdx = batchSize * i;
|
||||||
|
if (i == batches) {
|
||||||
|
endIdx = startIdx + (total % batchSize);
|
||||||
|
}
|
||||||
|
if(log.isDebugEnabled()) {
|
||||||
|
log.debug("\n\n############ Iterating over batch " + i + "[" +
|
||||||
|
startIdx + "," + endIdx + "] #######");
|
||||||
|
}
|
||||||
|
List<Integer> subList = candidates.subList(startIdx, endIdx);
|
||||||
|
prepareTempTable(subList);
|
||||||
|
|
||||||
|
//Purge the largest table, DM_DEVICE_OPERATION_RESPONSE
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Purging operation responses");
|
||||||
|
}
|
||||||
|
archivalDAO.moveOperationResponses();
|
||||||
|
|
||||||
|
//Purge the notifications table, DM_NOTIFICATION
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Purging notifications");
|
||||||
|
}
|
||||||
|
archivalDAO.moveNotifications();
|
||||||
|
|
||||||
|
//Purge the command operations table, DM_COMMAND_OPERATION
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Purging command operations");
|
||||||
|
}
|
||||||
|
archivalDAO.moveCommandOperations();
|
||||||
|
|
||||||
|
//Purge the profile operation table, DM_PROFILE_OPERATION
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Purging profile operations");
|
||||||
|
}
|
||||||
|
archivalDAO.moveProfileOperations();
|
||||||
|
|
||||||
|
//Purge the enrolment mappings table, DM_ENROLMENT_OP_MAPPING
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Purging enrolment mappings");
|
||||||
|
}
|
||||||
|
archivalDAO.moveEnrolmentMappings();
|
||||||
|
|
||||||
|
//Finally, purge the operations table, DM_OPERATION
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Purging operations");
|
||||||
|
}
|
||||||
|
archivalDAO.moveOperations();
|
||||||
|
}
|
||||||
|
commitTransactions();
|
||||||
|
} catch (ArchivalDAOException e) {
|
||||||
|
rollbackTransactions();
|
||||||
|
throw new ArchivalException("An error occurred while data archival", e);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalException("An error occurred while connecting to the archival database.", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalSourceDAOFactory.closeConnection();
|
||||||
|
ArchivalDestinationDAOFactory.closeConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareTempTable(List<Integer> subList) throws ArchivalDAOException {
|
||||||
|
//Clean up the DM_ARCHIVED_OPERATIONS table
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Truncating the temporary table");
|
||||||
|
}
|
||||||
|
archivalDAO.truncateOperationIDsForArchival();
|
||||||
|
archivalDAO.copyOperationIDsForArchival(subList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void beginTransactions() throws ArchivalException {
|
||||||
|
try {
|
||||||
|
ArchivalSourceDAOFactory.beginTransaction();
|
||||||
|
ArchivalDestinationDAOFactory.beginTransaction();
|
||||||
|
} catch (TransactionManagementException e) {
|
||||||
|
log.error("An error occurred during starting transactions", e);
|
||||||
|
throw new ArchivalException("An error occurred during starting transactions", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void commitTransactions() {
|
||||||
|
ArchivalSourceDAOFactory.commitTransaction();
|
||||||
|
ArchivalDestinationDAOFactory.commitTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rollbackTransactions() {
|
||||||
|
ArchivalSourceDAOFactory.rollbackTransaction();
|
||||||
|
ArchivalDestinationDAOFactory.rollbackTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int calculateNumberOfBatches(int total) {
|
||||||
|
int batches = 0;
|
||||||
|
int batchSize = ITERATION_COUNT;
|
||||||
|
if ((total % batchSize) > 0) {
|
||||||
|
batches = (total / batchSize) + 1;
|
||||||
|
} else {
|
||||||
|
batches = total / batchSize;
|
||||||
|
}
|
||||||
|
return batches;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteArchivedRecords() throws ArchivalException {
|
||||||
|
try {
|
||||||
|
ArchivalDestinationDAOFactory.openConnection();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Deleting operation responses");
|
||||||
|
}
|
||||||
|
dataDeletionDAO.deleteOperationResponses();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Deleting notifications ");
|
||||||
|
}
|
||||||
|
dataDeletionDAO.deleteNotifications();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Deleting command operations");
|
||||||
|
}
|
||||||
|
dataDeletionDAO.deleteCommandOperations();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Deleting profile operations ");
|
||||||
|
}
|
||||||
|
dataDeletionDAO.deleteProfileOperations();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Deleting enrolment mappings ");
|
||||||
|
}
|
||||||
|
dataDeletionDAO.deleteEnrolmentMappings();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("## Deleting operations ");
|
||||||
|
}
|
||||||
|
dataDeletionDAO.deleteOperations();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalException("An error occurred while initialising data source for archival", e);
|
||||||
|
} catch (ArchivalDAOException e) {
|
||||||
|
log.error("An error occurred while executing DataDeletionTask");
|
||||||
|
} finally {
|
||||||
|
ArchivalDestinationDAOFactory.closeConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.archival.dao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operations to move data from DM database to archival database
|
||||||
|
*/
|
||||||
|
public interface ArchivalDAO {
|
||||||
|
|
||||||
|
int DEFAULT_BATCH_SIZE = 1000;
|
||||||
|
|
||||||
|
List<Integer> getAllOperations() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
List<Integer> getPendingAndInProgressOperations() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void copyOperationIDsForArchival(List<Integer> operationIds) throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void moveOperationResponses() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void moveNotifications() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void moveCommandOperations() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void moveProfileOperations() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void moveEnrolmentMappings() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void moveOperations() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void truncateOperationIDsForArchival() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.archival.dao;
|
||||||
|
|
||||||
|
|
||||||
|
public class ArchivalDAOException extends Exception {
|
||||||
|
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
public String getErrorMessage() {
|
||||||
|
return errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrorMessage(String errorMessage) {
|
||||||
|
this.errorMessage = errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchivalDAOException(String message) {
|
||||||
|
super(message);
|
||||||
|
setErrorMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchivalDAOException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
setErrorMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ArchivalDAOException(String message, Throwable cause, boolean enableSuppression,
|
||||||
|
boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
setErrorMessage(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.archival.dao;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
public class ArchivalDAOUtil {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(ArchivalDAOUtil.class);
|
||||||
|
|
||||||
|
public static void cleanupResources(Statement stmt, ResultSet rs) {
|
||||||
|
if (rs != null) {
|
||||||
|
try {
|
||||||
|
rs.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.warn("Error occurred while closing the result set", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stmt != null) {
|
||||||
|
try {
|
||||||
|
stmt.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.warn("Error occurred while closing the statement", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void cleanupResources(Statement stmt) {
|
||||||
|
if (stmt != null) {
|
||||||
|
try {
|
||||||
|
stmt.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.warn("Error occurred while closing the statement", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.archival.dao;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.wso2.carbon.device.mgt.common.IllegalTransactionStateException;
|
||||||
|
import org.wso2.carbon.device.mgt.common.TransactionManagementException;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.dao.impl.DataDeletionDAOImpl;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.datasource.DataSourceConfig;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.datasource.JNDILookupDefinition;
|
||||||
|
import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
|
||||||
|
import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOFactory;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ArchivalDestinationDAOFactory {
|
||||||
|
private static final Log log = LogFactory.getLog(OperationManagementDAOFactory.class);
|
||||||
|
private static DataSource dataSource;
|
||||||
|
private static String databaseEngine;
|
||||||
|
private static int retentionPeriod;
|
||||||
|
private static ThreadLocal<Connection> currentConnection = new ThreadLocal<Connection>();
|
||||||
|
|
||||||
|
public static DataDeletionDAO getDataDeletionDAO() {
|
||||||
|
return new DataDeletionDAOImpl(DeviceConfigurationManager.getInstance().getDeviceManagementConfig()
|
||||||
|
.getArchivalConfiguration().getArchivalTaskConfiguration()
|
||||||
|
.getPurgingTaskConfiguration().getRetentionPeriod());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init(DataSource dtSource) {
|
||||||
|
dataSource = dtSource;
|
||||||
|
try {
|
||||||
|
databaseEngine = dataSource.getConnection().getMetaData().getDatabaseProductName();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("Error occurred while retrieving config.datasource connection", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init(DataSourceConfig config) {
|
||||||
|
dataSource = resolveDataSource(config);
|
||||||
|
try {
|
||||||
|
databaseEngine = dataSource.getConnection().getMetaData().getDatabaseProductName();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("Error occurred while retrieving config.datasource connection", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void beginTransaction() throws TransactionManagementException {
|
||||||
|
try {
|
||||||
|
Connection conn = dataSource.getConnection();
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
currentConnection.set(conn);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new TransactionManagementException(
|
||||||
|
"Error occurred while retrieving config.datasource connection", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void openConnection() throws SQLException {
|
||||||
|
currentConnection.set(dataSource.getConnection());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Connection getConnection() throws SQLException {
|
||||||
|
if (currentConnection.get() == null) {
|
||||||
|
throw new IllegalTransactionStateException("No connection is associated with the current transaction. " +
|
||||||
|
"This might have ideally caused by not properly initiating the transaction via " +
|
||||||
|
"'beginTransaction'/'openConnection' methods");
|
||||||
|
}
|
||||||
|
return currentConnection.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void closeConnection() {
|
||||||
|
Connection con = currentConnection.get();
|
||||||
|
if (con != null) {
|
||||||
|
try {
|
||||||
|
con.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("Error occurred while close the connection");
|
||||||
|
}
|
||||||
|
currentConnection.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void commitTransaction() {
|
||||||
|
try {
|
||||||
|
Connection conn = currentConnection.get();
|
||||||
|
if (conn != null) {
|
||||||
|
conn.commit();
|
||||||
|
} else {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Datasource connection associated with the current thread is null, hence commit " +
|
||||||
|
"has not been attempted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("Error occurred while committing the transaction", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void rollbackTransaction() {
|
||||||
|
try {
|
||||||
|
Connection conn = currentConnection.get();
|
||||||
|
if (conn != null) {
|
||||||
|
conn.rollback();
|
||||||
|
} else {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Datasource connection associated with the current thread is null, hence rollback " +
|
||||||
|
"has not been attempted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("Error occurred while roll-backing the transaction", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve data source from the data source definition
|
||||||
|
*
|
||||||
|
* @param config data source configuration
|
||||||
|
* @return data source resolved from the data source definition
|
||||||
|
*/
|
||||||
|
private static DataSource resolveDataSource(DataSourceConfig config) {
|
||||||
|
DataSource dataSource = null;
|
||||||
|
if (config == null) {
|
||||||
|
throw new RuntimeException("Device Management Repository data source configuration is null and " +
|
||||||
|
"thus, is not initialized");
|
||||||
|
}
|
||||||
|
JNDILookupDefinition jndiConfig = config.getJndiLookupDefinition();
|
||||||
|
if (jndiConfig != null) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Initializing Device Management Repository data source using the JNDI Lookup Definition");
|
||||||
|
}
|
||||||
|
List<JNDILookupDefinition.JNDIProperty> jndiPropertyList = jndiConfig.getJndiProperties();
|
||||||
|
if (jndiPropertyList != null) {
|
||||||
|
Hashtable<Object, Object> jndiProperties = new Hashtable<Object, Object>();
|
||||||
|
for (JNDILookupDefinition.JNDIProperty prop : jndiPropertyList) {
|
||||||
|
jndiProperties.put(prop.getName(), prop.getValue());
|
||||||
|
}
|
||||||
|
dataSource = DeviceManagementDAOUtil.lookupDataSource(jndiConfig.getJndiName(), jndiProperties);
|
||||||
|
} else {
|
||||||
|
dataSource = DeviceManagementDAOUtil.lookupDataSource(jndiConfig.getJndiName(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.archival.dao;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.wso2.carbon.device.mgt.common.IllegalTransactionStateException;
|
||||||
|
import org.wso2.carbon.device.mgt.common.TransactionManagementException;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.dao.impl.ArchivalDAOImpl;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.archival.ArchivalTaskConfiguration;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.datasource.DataSourceConfig;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.datasource.JNDILookupDefinition;
|
||||||
|
import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
|
||||||
|
import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOFactory;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ArchivalSourceDAOFactory {
|
||||||
|
private static final Log log = LogFactory.getLog(OperationManagementDAOFactory.class);
|
||||||
|
private static DataSource dataSource;
|
||||||
|
private static String databaseEngine;
|
||||||
|
private static ThreadLocal<Connection> currentConnection = new ThreadLocal<Connection>();
|
||||||
|
|
||||||
|
public static ArchivalDAO getDataPurgingDAO() {
|
||||||
|
ArchivalTaskConfiguration configuration = DeviceConfigurationManager.getInstance()
|
||||||
|
.getDeviceManagementConfig()
|
||||||
|
.getArchivalConfiguration()
|
||||||
|
.getArchivalTaskConfiguration();
|
||||||
|
return new ArchivalDAOImpl(configuration.getRetentionPeriod(), configuration.getBatchSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init(DataSource dtSource) {
|
||||||
|
dataSource = dtSource;
|
||||||
|
try {
|
||||||
|
databaseEngine = dataSource.getConnection().getMetaData().getDatabaseProductName();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("Error occurred while retrieving config.datasource connection", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init(DataSourceConfig config) {
|
||||||
|
dataSource = resolveDataSource(config);
|
||||||
|
try {
|
||||||
|
databaseEngine = dataSource.getConnection().getMetaData().getDatabaseProductName();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("Error occurred while retrieving config.datasource connection", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void beginTransaction() throws TransactionManagementException {
|
||||||
|
try {
|
||||||
|
Connection conn = dataSource.getConnection();
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
currentConnection.set(conn);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new TransactionManagementException(
|
||||||
|
"Error occurred while retrieving config.datasource connection", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void openConnection() throws SQLException {
|
||||||
|
currentConnection.set(dataSource.getConnection());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Connection getConnection() throws SQLException {
|
||||||
|
if (currentConnection.get() == null) {
|
||||||
|
throw new IllegalTransactionStateException("No connection is associated with the current transaction. " +
|
||||||
|
"This might have ideally caused by not properly initiating the transaction via " +
|
||||||
|
"'beginTransaction'/'openConnection' methods");
|
||||||
|
}
|
||||||
|
return currentConnection.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void closeConnection() {
|
||||||
|
Connection con = currentConnection.get();
|
||||||
|
if (con != null) {
|
||||||
|
try {
|
||||||
|
con.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("Error occurred while close the connection");
|
||||||
|
}
|
||||||
|
currentConnection.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void commitTransaction() {
|
||||||
|
try {
|
||||||
|
Connection conn = currentConnection.get();
|
||||||
|
if (conn != null) {
|
||||||
|
conn.commit();
|
||||||
|
} else {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Datasource connection associated with the current thread is null, hence commit " +
|
||||||
|
"has not been attempted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("Error occurred while committing the transaction", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void rollbackTransaction() {
|
||||||
|
try {
|
||||||
|
Connection conn = currentConnection.get();
|
||||||
|
if (conn != null) {
|
||||||
|
conn.rollback();
|
||||||
|
} else {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Datasource connection associated with the current thread is null, hence rollback " +
|
||||||
|
"has not been attempted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("Error occurred while roll-backing the transaction", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve data source from the data source definition
|
||||||
|
*
|
||||||
|
* @param config data source configuration
|
||||||
|
* @return data source resolved from the data source definition
|
||||||
|
*/
|
||||||
|
private static DataSource resolveDataSource(DataSourceConfig config) {
|
||||||
|
DataSource dataSource = null;
|
||||||
|
if (config == null) {
|
||||||
|
throw new RuntimeException("Device Management Repository data source configuration is null and " +
|
||||||
|
"thus, is not initialized");
|
||||||
|
}
|
||||||
|
JNDILookupDefinition jndiConfig = config.getJndiLookupDefinition();
|
||||||
|
if (jndiConfig != null) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Initializing Device Management Repository data source using the JNDI Lookup Definition");
|
||||||
|
}
|
||||||
|
List<JNDILookupDefinition.JNDIProperty> jndiPropertyList = jndiConfig.getJndiProperties();
|
||||||
|
if (jndiPropertyList != null) {
|
||||||
|
Hashtable<Object, Object> jndiProperties = new Hashtable<Object, Object>();
|
||||||
|
for (JNDILookupDefinition.JNDIProperty prop : jndiPropertyList) {
|
||||||
|
jndiProperties.put(prop.getName(), prop.getValue());
|
||||||
|
}
|
||||||
|
dataSource = DeviceManagementDAOUtil.lookupDataSource(jndiConfig.getJndiName(), jndiProperties);
|
||||||
|
} else {
|
||||||
|
dataSource = DeviceManagementDAOUtil.lookupDataSource(jndiConfig.getJndiName(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.archival.dao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operations to permanently delete data from archived database tables
|
||||||
|
*/
|
||||||
|
public interface DataDeletionDAO {
|
||||||
|
|
||||||
|
int DEFAULT_RETENTION_PERIOD = 364;
|
||||||
|
|
||||||
|
void deleteOperationResponses() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void deleteNotifications() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void deleteCommandOperations() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void deleteProfileOperations() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void deleteEnrolmentMappings() throws ArchivalDAOException;
|
||||||
|
|
||||||
|
void deleteOperations() throws ArchivalDAOException;
|
||||||
|
}
|
@ -0,0 +1,471 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.archival.dao.impl;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.dao.*;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ArchivalDAOImpl implements ArchivalDAO {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(ArchivalDAOImpl.class);
|
||||||
|
|
||||||
|
private int retentionPeriod;
|
||||||
|
private int batchSize = ArchivalDAO.DEFAULT_BATCH_SIZE;
|
||||||
|
private Timestamp currentTimestamp;
|
||||||
|
|
||||||
|
|
||||||
|
public ArchivalDAOImpl(int retentionPeriod) {
|
||||||
|
this.retentionPeriod = retentionPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchivalDAOImpl(int retentionPeriod, int batchSize) {
|
||||||
|
this.retentionPeriod = retentionPeriod;
|
||||||
|
this.batchSize = batchSize;
|
||||||
|
this.currentTimestamp = new Timestamp(new java.util.Date().getTime());
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Using batch size of " + this.batchSize + " with retention period " + this.retentionPeriod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Integer> getAllOperations() throws ArchivalDAOException {
|
||||||
|
List<Integer> operationIds = new ArrayList<>();
|
||||||
|
Statement stmt = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalSourceDAOFactory.getConnection();
|
||||||
|
String sql = "SELECT DISTINCT OPERATION_ID FROM DM_ENROLMENT_OP_MAPPING " +
|
||||||
|
"WHERE CREATED_TIMESTAMP BETWEEN DATE_SUB(NOW(), INTERVAL " +
|
||||||
|
this.retentionPeriod + " DAY) AND NOW()";
|
||||||
|
stmt = this.createMemoryEfficientStatement(conn);
|
||||||
|
rs = stmt.executeQuery(sql);
|
||||||
|
while (rs.next()) {
|
||||||
|
operationIds.add(rs.getInt("OPERATION_ID"));
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("An error occurred while getting a list operation Ids to archive", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt, rs);
|
||||||
|
}
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(operationIds.size() + " operations found for the archival");
|
||||||
|
}
|
||||||
|
return operationIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Integer> getPendingAndInProgressOperations() throws ArchivalDAOException {
|
||||||
|
List<Integer> operationIds = new ArrayList<>();
|
||||||
|
Statement stmt = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalSourceDAOFactory.getConnection();
|
||||||
|
String sql = "SELECT DISTINCT OPERATION_ID " +
|
||||||
|
" FROM DM_ENROLMENT_OP_MAPPING WHERE STATUS IN('PENDING', 'IN_PROGRESS') " +
|
||||||
|
" AND CREATED_TIMESTAMP BETWEEN DATE_SUB(NOW(), INTERVAL " + this.retentionPeriod +" DAY) AND NOW()";
|
||||||
|
stmt = this.createMemoryEfficientStatement(conn);
|
||||||
|
rs = stmt.executeQuery(sql);
|
||||||
|
while (rs.next()) {
|
||||||
|
operationIds.add(rs.getInt("OPERATION_ID"));
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("An error occurred while getting a list operation Ids to archive", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt, rs);
|
||||||
|
}
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(operationIds.size() + " PENDING and IN_PROFRESS operations found for the archival");
|
||||||
|
}
|
||||||
|
return operationIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyOperationIDsForArchival(List<Integer> operationIds) throws ArchivalDAOException {
|
||||||
|
PreparedStatement stmt = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalSourceDAOFactory.getConnection();
|
||||||
|
String sql = "INSERT INTO DM_ARCHIVED_OPERATIONS(ID,CREATED_TIMESTAMP) VALUES (?,NOW())";
|
||||||
|
stmt = conn.prepareStatement(sql);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < operationIds.size(); i++) {
|
||||||
|
stmt.setInt(1, operationIds.get(i));
|
||||||
|
stmt.addBatch();
|
||||||
|
|
||||||
|
if (++count % this.batchSize == 0) {
|
||||||
|
stmt.executeBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt.executeBatch();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(count + " Records copied to the temporary table.");
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error while copying operation Ids for archival", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveOperationResponses() throws ArchivalDAOException {
|
||||||
|
Statement stmt = null;
|
||||||
|
PreparedStatement stmt2 = null;
|
||||||
|
Statement stmt3 = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalSourceDAOFactory.getConnection();
|
||||||
|
String sql = "SELECT * FROM DM_DEVICE_OPERATION_RESPONSE WHERE OPERATION_ID IN " +
|
||||||
|
"(SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt = this.createMemoryEfficientStatement(conn);
|
||||||
|
rs = stmt.executeQuery(sql);
|
||||||
|
|
||||||
|
Connection conn2 = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
sql = "INSERT INTO DM_DEVICE_OPERATION_RESPONSE_ARCH VALUES(?, ?, ?, ?, ?,?,?)";
|
||||||
|
stmt2 = conn2.prepareStatement(sql);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while (rs.next()) {
|
||||||
|
stmt2.setInt(1, rs.getInt("ID"));
|
||||||
|
stmt2.setInt(2, rs.getInt("ENROLMENT_ID"));
|
||||||
|
stmt2.setInt(3, rs.getInt("OPERATION_ID"));
|
||||||
|
stmt2.setInt(4, rs.getInt("EN_OP_MAP_ID"));
|
||||||
|
stmt2.setBytes(5, rs.getBytes("OPERATION_RESPONSE"));
|
||||||
|
stmt2.setTimestamp(6, rs.getTimestamp("RECEIVED_TIMESTAMP"));
|
||||||
|
stmt2.setTimestamp(7, this.currentTimestamp);
|
||||||
|
stmt2.addBatch();
|
||||||
|
|
||||||
|
if (++count % batchSize == 0) {
|
||||||
|
stmt2.executeBatch();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Executing batch " + count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt2.executeBatch();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(count + " [OPERATION_RESPONSES] Records copied to the archival table. Starting deletion");
|
||||||
|
}
|
||||||
|
//try the deletion now
|
||||||
|
sql = "DELETE FROM DM_DEVICE_OPERATION_RESPONSE WHERE OPERATION_ID IN (" +
|
||||||
|
" SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt3 = conn.createStatement();
|
||||||
|
int affected = stmt3.executeUpdate(sql);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(affected + " Rows deleted");
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while moving operations ", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt, rs);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt2);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveNotifications() throws ArchivalDAOException {
|
||||||
|
Statement stmt = null;
|
||||||
|
PreparedStatement stmt2 = null;
|
||||||
|
Statement stmt3 = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalSourceDAOFactory.getConnection();
|
||||||
|
String sql = "SELECT * FROM DM_NOTIFICATION WHERE OPERATION_ID IN (SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt = this.createMemoryEfficientStatement(conn);
|
||||||
|
rs = stmt.executeQuery(sql);
|
||||||
|
|
||||||
|
// ArchivalDestinationDAOFactory.beginTransaction();
|
||||||
|
Connection conn2 = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
|
||||||
|
sql = "INSERT INTO DM_NOTIFICATION_ARCH VALUES(?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
stmt2 = conn2.prepareStatement(sql);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while (rs.next()) {
|
||||||
|
stmt2.setInt(1, rs.getInt("NOTIFICATION_ID"));
|
||||||
|
stmt2.setInt(2, rs.getInt("DEVICE_ID"));
|
||||||
|
stmt2.setInt(3, rs.getInt("OPERATION_ID"));
|
||||||
|
stmt2.setInt(4, rs.getInt("TENANT_ID"));
|
||||||
|
stmt2.setString(5, rs.getString("STATUS"));
|
||||||
|
stmt2.setString(6, rs.getString("DESCRIPTION"));
|
||||||
|
stmt2.setTimestamp(7, this.currentTimestamp);
|
||||||
|
stmt2.addBatch();
|
||||||
|
|
||||||
|
if (++count % batchSize == 0) {
|
||||||
|
stmt2.executeBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt2.executeBatch();
|
||||||
|
// ArchivalDestinationDAOFactory.commitTransaction();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(count + " [NOTIFICATIONS] Records copied to the archival table. Starting deletion");
|
||||||
|
}
|
||||||
|
sql = "DELETE FROM DM_NOTIFICATION" +
|
||||||
|
" WHERE OPERATION_ID IN (SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt3 = conn.createStatement();
|
||||||
|
int affected = stmt3.executeUpdate(sql);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(affected + " Rows deleted");
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while moving notifications ", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt, rs);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt2);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveCommandOperations() throws ArchivalDAOException {
|
||||||
|
Statement stmt = null;
|
||||||
|
PreparedStatement stmt2 = null;
|
||||||
|
Statement stmt3 = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalSourceDAOFactory.getConnection();
|
||||||
|
String sql = "SELECT * FROM DM_COMMAND_OPERATION WHERE OPERATION_ID IN " +
|
||||||
|
"(SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt = this.createMemoryEfficientStatement(conn);
|
||||||
|
rs = stmt.executeQuery(sql);
|
||||||
|
|
||||||
|
Connection conn2 = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
|
||||||
|
sql = "INSERT INTO DM_COMMAND_OPERATION_ARCH VALUES(?,?,?)";
|
||||||
|
stmt2 = conn2.prepareStatement(sql);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while (rs.next()) {
|
||||||
|
stmt2.setInt(1, rs.getInt("OPERATION_ID"));
|
||||||
|
stmt2.setInt(2, rs.getInt("ENABLED"));
|
||||||
|
stmt2.setTimestamp(3, this.currentTimestamp);
|
||||||
|
stmt2.addBatch();
|
||||||
|
|
||||||
|
if (++count % batchSize == 0) {
|
||||||
|
stmt2.executeBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt2.executeBatch();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(count + " [COMMAND_OPERATION] Records copied to the archival table. Starting deletion");
|
||||||
|
}
|
||||||
|
sql = "DELETE FROM DM_COMMAND_OPERATION" +
|
||||||
|
" WHERE OPERATION_ID IN (SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt3 = conn.createStatement();
|
||||||
|
int affected = stmt3.executeUpdate(sql);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(affected + " Rows deleted");
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while moving command operations", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt, rs);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt2);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveProfileOperations() throws ArchivalDAOException {
|
||||||
|
Statement stmt = null;
|
||||||
|
PreparedStatement stmt2 = null;
|
||||||
|
Statement stmt3 = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalSourceDAOFactory.getConnection();
|
||||||
|
String sql = "SELECT * FROM DM_PROFILE_OPERATION WHERE OPERATION_ID IN " +
|
||||||
|
"(SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt = this.createMemoryEfficientStatement(conn);
|
||||||
|
rs = stmt.executeQuery(sql);
|
||||||
|
|
||||||
|
Connection conn2 = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
|
||||||
|
sql = "INSERT INTO DM_PROFILE_OPERATION_ARCH VALUES(?, ?, ?, ?)";
|
||||||
|
stmt2 = conn2.prepareStatement(sql);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while (rs.next()) {
|
||||||
|
stmt2.setInt(1, rs.getInt("OPERATION_ID"));
|
||||||
|
stmt2.setInt(2, rs.getInt("ENABLED"));
|
||||||
|
stmt2.setBytes(3, rs.getBytes("OPERATION_DETAILS"));
|
||||||
|
stmt2.setTimestamp(4,this.currentTimestamp );
|
||||||
|
stmt2.addBatch();
|
||||||
|
|
||||||
|
if (++count % batchSize == 0) {
|
||||||
|
stmt2.executeBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt2.executeBatch();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(count + " [PROFILE_OPERATION] Records copied to the archival table. Starting deletion");
|
||||||
|
}
|
||||||
|
sql = "DELETE FROM DM_PROFILE_OPERATION" +
|
||||||
|
" WHERE OPERATION_ID IN (SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt3 = conn.createStatement();
|
||||||
|
int affected = stmt3.executeUpdate(sql);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(affected + " Rows deleted");
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while moving profile operations", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt, rs);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt2);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveEnrolmentMappings() throws ArchivalDAOException {
|
||||||
|
Statement stmt = null;
|
||||||
|
PreparedStatement stmt2 = null;
|
||||||
|
Statement stmt3 = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalSourceDAOFactory.getConnection();
|
||||||
|
String sql = "SELECT * FROM DM_ENROLMENT_OP_MAPPING WHERE OPERATION_ID IN " +
|
||||||
|
"(SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt = this.createMemoryEfficientStatement(conn);
|
||||||
|
rs = stmt.executeQuery(sql);
|
||||||
|
|
||||||
|
Connection conn2 = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
|
||||||
|
sql = "INSERT INTO DM_ENROLMENT_OP_MAPPING_ARCH VALUES(?, ?, ?, ?, ?, ?, ?,?)";
|
||||||
|
stmt2 = conn2.prepareStatement(sql);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while (rs.next()) {
|
||||||
|
stmt2.setInt(1, rs.getInt("ID"));
|
||||||
|
stmt2.setInt(2, rs.getInt("ENROLMENT_ID"));
|
||||||
|
stmt2.setInt(3, rs.getInt("OPERATION_ID"));
|
||||||
|
stmt2.setString(4, rs.getString("STATUS"));
|
||||||
|
stmt2.setString(5, rs.getString("PUSH_NOTIFICATION_STATUS"));
|
||||||
|
stmt2.setInt(6, rs.getInt("CREATED_TIMESTAMP"));
|
||||||
|
stmt2.setInt(7, rs.getInt("UPDATED_TIMESTAMP"));
|
||||||
|
stmt2.setTimestamp(8, this.currentTimestamp);
|
||||||
|
stmt2.addBatch();
|
||||||
|
|
||||||
|
if (++count % batchSize == 0) {
|
||||||
|
stmt2.executeBatch();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Executing batch " + count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt2.executeBatch();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(count + " [ENROLMENT_OP_MAPPING] Records copied to the archival table. Starting deletion");
|
||||||
|
}
|
||||||
|
sql = "DELETE FROM DM_ENROLMENT_OP_MAPPING WHERE OPERATION_ID IN (" +
|
||||||
|
"SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt3 = conn.createStatement();
|
||||||
|
int affected = stmt3.executeUpdate(sql);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(affected + " Rows deleted");
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while moving enrolment mappings", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt, rs);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt2);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveOperations() throws ArchivalDAOException {
|
||||||
|
Statement stmt = null;
|
||||||
|
PreparedStatement stmt2 = null;
|
||||||
|
Statement stmt3 = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalSourceDAOFactory.getConnection();
|
||||||
|
String sql = "SELECT * FROM DM_OPERATION WHERE ID IN (SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt = this.createMemoryEfficientStatement(conn);
|
||||||
|
rs = stmt.executeQuery(sql);
|
||||||
|
|
||||||
|
Connection conn2 = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
sql = "INSERT INTO DM_OPERATION_ARCH VALUES(?, ?, ?, ?, ?, ?)";
|
||||||
|
stmt2 = conn2.prepareStatement(sql);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while (rs.next()) {
|
||||||
|
stmt2.setInt(1, rs.getInt("ID"));
|
||||||
|
stmt2.setString(2, rs.getString("TYPE"));
|
||||||
|
stmt2.setTimestamp(3, rs.getTimestamp("CREATED_TIMESTAMP"));
|
||||||
|
stmt2.setTimestamp(4, rs.getTimestamp("RECEIVED_TIMESTAMP"));
|
||||||
|
stmt2.setString(5, rs.getString("OPERATION_CODE"));
|
||||||
|
stmt2.setTimestamp(6, this.currentTimestamp);
|
||||||
|
stmt2.addBatch();
|
||||||
|
|
||||||
|
if (++count % batchSize == 0) {
|
||||||
|
stmt2.executeBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt2.executeBatch();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(count + " [OPERATIONS] Records copied to the archival table. Starting deletion");
|
||||||
|
}
|
||||||
|
sql = "DELETE FROM DM_OPERATION WHERE ID IN (" +
|
||||||
|
"SELECT ID FROM DM_ARCHIVED_OPERATIONS)";
|
||||||
|
stmt3 = conn.createStatement();
|
||||||
|
int affected = stmt3.executeUpdate(sql);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(affected + " Rows deleted");
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while moving operations", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt, rs);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt2);
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void truncateOperationIDsForArchival() throws ArchivalDAOException {
|
||||||
|
PreparedStatement stmt = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalSourceDAOFactory.getConnection();
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
String sql = "TRUNCATE DM_ARCHIVED_OPERATIONS";
|
||||||
|
stmt = conn.prepareStatement(sql);
|
||||||
|
stmt.addBatch();
|
||||||
|
stmt.executeBatch();
|
||||||
|
conn.commit();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while truncating operation Ids", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Statement createMemoryEfficientStatement(Connection conn) throws ArchivalDAOException, SQLException {
|
||||||
|
Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||||
|
stmt.setFetchSize(Integer.MIN_VALUE);
|
||||||
|
return stmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.archival.dao.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.dao.ArchivalDAOException;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.dao.ArchivalDAOUtil;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.dao.ArchivalDestinationDAOFactory;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.dao.DataDeletionDAO;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
public class DataDeletionDAOImpl implements DataDeletionDAO {
|
||||||
|
private static Log log = LogFactory.getLog(DataDeletionDAOImpl.class);
|
||||||
|
|
||||||
|
private int retentionPeriod = DataDeletionDAO.DEFAULT_RETENTION_PERIOD;
|
||||||
|
|
||||||
|
public DataDeletionDAOImpl(int retentionPeriod) {
|
||||||
|
this.retentionPeriod = retentionPeriod;
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Using retention period as " + retentionPeriod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteOperationResponses() throws ArchivalDAOException {
|
||||||
|
PreparedStatement stmt = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
String sql = "DELETE FROM DM_DEVICE_OPERATION_RESPONSE_ARCH " +
|
||||||
|
"WHERE ARCHIVED_AT < DATE_SUB(NOW(), INTERVAL ? DAY)";
|
||||||
|
stmt = conn.prepareStatement(sql);
|
||||||
|
stmt.setInt(1, this.retentionPeriod);
|
||||||
|
stmt.addBatch();
|
||||||
|
stmt.executeBatch();
|
||||||
|
conn.commit();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while deleting operation responses", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteNotifications() throws ArchivalDAOException {
|
||||||
|
PreparedStatement stmt = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
String sql = "DELETE FROM DM_NOTIFICATION_ARCH" +
|
||||||
|
" WHERE ARCHIVED_AT < DATE_SUB(NOW(), INTERVAL ? DAY)";
|
||||||
|
stmt = conn.prepareStatement(sql);
|
||||||
|
stmt.setInt(1, this.retentionPeriod);
|
||||||
|
stmt.addBatch();
|
||||||
|
stmt.executeBatch();
|
||||||
|
conn.commit();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while deleting notifications", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteCommandOperations() throws ArchivalDAOException {
|
||||||
|
PreparedStatement stmt = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
String sql = "DELETE FROM DM_COMMAND_OPERATION_ARCH" +
|
||||||
|
" WHERE ARCHIVED_AT < DATE_SUB(NOW(), INTERVAL ? DAY)";
|
||||||
|
stmt = conn.prepareStatement(sql);
|
||||||
|
stmt.setInt(1, this.retentionPeriod);
|
||||||
|
stmt.addBatch();
|
||||||
|
stmt.executeBatch();
|
||||||
|
conn.commit();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while deleting command operations", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteProfileOperations() throws ArchivalDAOException {
|
||||||
|
PreparedStatement stmt = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
String sql = "DELETE FROM DM_PROFILE_OPERATION_ARCH" +
|
||||||
|
" WHERE ARCHIVED_AT < DATE_SUB(NOW(), INTERVAL ? DAY)";
|
||||||
|
stmt = conn.prepareStatement(sql);
|
||||||
|
stmt.setInt(1, this.retentionPeriod);
|
||||||
|
stmt.addBatch();
|
||||||
|
stmt.executeBatch();
|
||||||
|
conn.commit();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while deleting profile operations", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteEnrolmentMappings() throws ArchivalDAOException {
|
||||||
|
PreparedStatement stmt = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
String sql = "DELETE FROM DM_ENROLMENT_OP_MAPPING_ARCH WHERE ARCHIVED_AT < DATE_SUB(NOW(), INTERVAL ? DAY)";
|
||||||
|
stmt = conn.prepareStatement(sql);
|
||||||
|
stmt.setInt(1, this.retentionPeriod);
|
||||||
|
stmt.addBatch();
|
||||||
|
stmt.executeBatch();
|
||||||
|
conn.commit();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while deleting enrolment mappings", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteOperations() throws ArchivalDAOException {
|
||||||
|
PreparedStatement stmt = null;
|
||||||
|
try {
|
||||||
|
Connection conn = ArchivalDestinationDAOFactory.getConnection();
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
String sql = "DELETE FROM DM_OPERATION_ARCH WHERE ARCHIVED_AT < DATE_SUB(NOW(), INTERVAL ? DAY)";
|
||||||
|
stmt = conn.prepareStatement(sql);
|
||||||
|
stmt.setInt(1, this.retentionPeriod);
|
||||||
|
stmt.addBatch();
|
||||||
|
stmt.executeBatch();
|
||||||
|
conn.commit();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new ArchivalDAOException("Error occurred while deleting operations", e);
|
||||||
|
} finally {
|
||||||
|
ArchivalDAOUtil.cleanupResources(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.config.archival;
|
||||||
|
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.datasource.DataSourceConfig;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents the information related to data archival configurations.
|
||||||
|
*/
|
||||||
|
@XmlRootElement(name = "ArchivalConfiguration")
|
||||||
|
public class ArchivalConfiguration {
|
||||||
|
|
||||||
|
private DataSourceConfig dataSourceConfig;
|
||||||
|
private ArchivalTaskConfiguration archivalTaskConfiguration;
|
||||||
|
|
||||||
|
@XmlElement(name = "DataSourceConfiguration", required = true)
|
||||||
|
public DataSourceConfig getDataSourceConfig() {
|
||||||
|
return dataSourceConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataSourceConfig(DataSourceConfig dataSourceConfig) {
|
||||||
|
this.dataSourceConfig = dataSourceConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "ArchivalTask", required = true)
|
||||||
|
public ArchivalTaskConfiguration getArchivalTaskConfiguration() {
|
||||||
|
return archivalTaskConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArchivalTaskConfiguration(ArchivalTaskConfiguration archivalTaskConfiguration) {
|
||||||
|
this.archivalTaskConfiguration = archivalTaskConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.config.archival;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
@XmlRootElement(name = "ArchivalTask")
|
||||||
|
public class ArchivalTaskConfiguration {
|
||||||
|
private boolean enabled;
|
||||||
|
private String cronExpression;
|
||||||
|
private String taskClazz;
|
||||||
|
private int retentionPeriod;
|
||||||
|
private int batchSize;
|
||||||
|
private PurgingTaskConfiguration purgingTaskConfiguration;
|
||||||
|
|
||||||
|
@XmlElement(name = "Enabled", required = true)
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "CronExpression", required = true)
|
||||||
|
public String getCronExpression() {
|
||||||
|
return cronExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCronExpression(String cronExpression) {
|
||||||
|
this.cronExpression = cronExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "TaskClass", required = true)
|
||||||
|
public String getTaskClazz() {
|
||||||
|
return taskClazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTaskClazz(String taskClazz) {
|
||||||
|
this.taskClazz = taskClazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "RetentionPeriod", required = true)
|
||||||
|
public int getRetentionPeriod() {
|
||||||
|
return retentionPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRetentionPeriod(int retentionPeriod) {
|
||||||
|
this.retentionPeriod = retentionPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "PurgingTask", required = true)
|
||||||
|
public PurgingTaskConfiguration getPurgingTaskConfiguration() {
|
||||||
|
return purgingTaskConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPurgingTaskConfiguration(PurgingTaskConfiguration purgingTaskConfiguration) {
|
||||||
|
this.purgingTaskConfiguration = purgingTaskConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name ="ExecutionBatchSize", required = true)
|
||||||
|
public int getBatchSize() {
|
||||||
|
return batchSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatchSize(int batchSize) {
|
||||||
|
this.batchSize = batchSize;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.config.archival;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
@XmlRootElement(name = "PurgingTask")
|
||||||
|
public class PurgingTaskConfiguration {
|
||||||
|
private boolean enabled;
|
||||||
|
private String cronExpression;
|
||||||
|
private String taskClazz;
|
||||||
|
private int retentionPeriod;
|
||||||
|
|
||||||
|
@XmlElement(name = "Enabled", required = true)
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "CronExpression", required = true)
|
||||||
|
public String getCronExpression() {
|
||||||
|
return cronExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCronExpression(String cronExpression) {
|
||||||
|
this.cronExpression = cronExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "TaskClass", required = true)
|
||||||
|
public String getTaskClazz() {
|
||||||
|
return taskClazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTaskClazz(String taskClazz) {
|
||||||
|
this.taskClazz = taskClazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "RetentionPeriod", required = true)
|
||||||
|
public int getRetentionPeriod() {
|
||||||
|
return retentionPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRetentionPeriod(int retentionPeriod) {
|
||||||
|
this.retentionPeriod = retentionPeriod;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.config.keymanager;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configurations related to key management.
|
||||||
|
*/
|
||||||
|
@XmlRootElement(name = "KeyManagerConfiguration")
|
||||||
|
public class KeyManagerConfigurations {
|
||||||
|
private String serverUrl;
|
||||||
|
private String adminUsername;
|
||||||
|
private String adminPassword;
|
||||||
|
|
||||||
|
@XmlElement(name = "AdminUsername", required = true)
|
||||||
|
public String getAdminUsername() {
|
||||||
|
return adminUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdminUsername(String adminUsername) {
|
||||||
|
this.adminUsername = adminUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "AdminPassword", required = true)
|
||||||
|
public String getAdminPassword() {
|
||||||
|
return adminPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdminPassword(String adminPassword) {
|
||||||
|
this.adminPassword = adminPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "ServerUrl", required = true)
|
||||||
|
public String getServerUrl() {
|
||||||
|
return serverUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerUrl(String serverUrl) {
|
||||||
|
this.serverUrl = serverUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.config.remote.session;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents the information related to Remote Session configuration.
|
||||||
|
*/
|
||||||
|
@XmlRootElement(name = "RemoteSessionConfiguration")
|
||||||
|
public class RemoteSessionConfiguration {
|
||||||
|
|
||||||
|
private String remoteSessionServerUrl;
|
||||||
|
private boolean enabled;
|
||||||
|
private int maxHTTPConnectionPerHost;
|
||||||
|
private int maxTotalHTTPConnections;
|
||||||
|
private int maxMessagesPerSecond;
|
||||||
|
private int sessionIdleTimeOut;
|
||||||
|
private int maxMessageBufferSize;
|
||||||
|
|
||||||
|
public void setRemoteSessionServerUrl(String remoteSessionServerUrl) {
|
||||||
|
this.remoteSessionServerUrl = remoteSessionServerUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remote session server url
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@XmlElement(name = "RemoteSessionServerUrl", required = true)
|
||||||
|
public String getRemoteSessionServerUrl() {
|
||||||
|
return remoteSessionServerUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remote session enabled
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@XmlElement(name = "Enabled", required = true)
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum connections per host for external http invocations
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@XmlElement(name = "MaximumHTTPConnectionPerHost", required = true, defaultValue = "2")
|
||||||
|
public int getMaxHTTPConnectionPerHost() {
|
||||||
|
return maxHTTPConnectionPerHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxHTTPConnectionPerHost(int maxHTTPConnectionPerHost) {
|
||||||
|
this.maxHTTPConnectionPerHost = maxHTTPConnectionPerHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum total connections for external http invocation
|
||||||
|
*/
|
||||||
|
@XmlElement(name = "MaximumTotalHTTPConnections", required = true, defaultValue = "100")
|
||||||
|
public int getMaxTotalHTTPConnections() {
|
||||||
|
return maxTotalHTTPConnections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxTotalHTTPConnections(int maxTotalHTTPConnections) {
|
||||||
|
this.maxTotalHTTPConnections = maxTotalHTTPConnections;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is for protect device from message spamming. Throttling limit in term of messages for device
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@XmlElement(name = "MaximumMessagesPerSecond", required = true, defaultValue = "10")
|
||||||
|
public int getMaxMessagesPerSession() {
|
||||||
|
return maxMessagesPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxMessagesPerSession(int maxMessagesPerSession) {
|
||||||
|
this.maxMessagesPerSecond = maxMessagesPerSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum idle timeout in minutes
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@XmlElement(name = "SessionIdleTimeOut", required = true, defaultValue = "5")
|
||||||
|
public int getSessionIdleTimeOut() {
|
||||||
|
return sessionIdleTimeOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSessionIdleTimeOut(int sessionIdleTimeOut) {
|
||||||
|
this.sessionIdleTimeOut = sessionIdleTimeOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum session buffer size in kilo bytes
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@XmlElement(name = "MaximumMessageBufferSize", required = true, defaultValue = "640")
|
||||||
|
public int getMaxMessageBufferSize() {
|
||||||
|
return maxMessageBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxMessageBufferSize(int MaxMessageBufferSize) {
|
||||||
|
this.maxMessageBufferSize = MaxMessageBufferSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
|||||||
|
package org.wso2.carbon.device.mgt.core.geo;
|
||||||
|
|
||||||
|
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
|
||||||
|
|
||||||
|
public class GeoCluster {
|
||||||
|
private GeoCoordinate coordinates;
|
||||||
|
private GeoCoordinate southWestBound;
|
||||||
|
private GeoCoordinate northEastBound;
|
||||||
|
private long count;
|
||||||
|
private String geohashPrefix;
|
||||||
|
private String deviceIdentification;
|
||||||
|
private String deviceType;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public GeoCluster(GeoCoordinate coordinates, GeoCoordinate southWestBound, GeoCoordinate northEastBound, long count,
|
||||||
|
String geohashPrefix, String deviceIdentification, String deviceType){
|
||||||
|
this.coordinates=coordinates;
|
||||||
|
this.southWestBound=southWestBound;
|
||||||
|
this.northEastBound=northEastBound;
|
||||||
|
this.count=count;
|
||||||
|
this.geohashPrefix=geohashPrefix;
|
||||||
|
this.deviceIdentification=deviceIdentification;
|
||||||
|
this.deviceType=deviceType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGeohashPrefix() {
|
||||||
|
return geohashPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeoCoordinate getCoordinates() {
|
||||||
|
return coordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeoCoordinate getSouthWestBound() {
|
||||||
|
return southWestBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeoCoordinate getNorthEastBound() {
|
||||||
|
return northEastBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceIdentification() {
|
||||||
|
return deviceIdentification;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceType() { return deviceType;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package org.wso2.carbon.device.mgt.core.geo.geoHash;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class GeoCoordinate {
|
||||||
|
private double latitude;
|
||||||
|
private double longitude;
|
||||||
|
|
||||||
|
public GeoCoordinate(double latitude, double longitude){
|
||||||
|
this.latitude=latitude;
|
||||||
|
this.longitude=longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLatitude() {
|
||||||
|
return latitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLongitude() {
|
||||||
|
return longitude;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package org.wso2.carbon.device.mgt.core.geo.geoHash;
|
||||||
|
|
||||||
|
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class GeoHashGenerator {
|
||||||
|
private static final String BASE_32 = "0123456789bcdefghjkmnpqrstuvwxyz";
|
||||||
|
private static final int GEOHASH_LENGTH = 16;
|
||||||
|
|
||||||
|
private GeoHashGenerator(){};
|
||||||
|
|
||||||
|
private static int divideRangeByValue(double value, double[] range) {
|
||||||
|
double mid = middle(range);
|
||||||
|
if (value >= mid) {
|
||||||
|
range[0] = mid;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
range[1] = mid;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void divideRangeByBit(int bit, double[] range) {
|
||||||
|
double mid = middle(range);
|
||||||
|
if (bit > 0) {
|
||||||
|
range[0] = mid;
|
||||||
|
} else {
|
||||||
|
range[1] = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double middle(double[] range) {
|
||||||
|
return (range[0] + range[1]) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String encodeGeohash(double latitude, double longitude) {
|
||||||
|
int geohashLength=GEOHASH_LENGTH;
|
||||||
|
double[] latRange = new double[]{-90.0, 90.0};
|
||||||
|
double[] lonRange = new double[]{-180.0, 180.0};
|
||||||
|
boolean isEven = true;
|
||||||
|
int bit = 0;
|
||||||
|
int base32CharIndex = 0;
|
||||||
|
StringBuilder geohash = new StringBuilder();
|
||||||
|
|
||||||
|
while (geohash.length() < geohashLength) {
|
||||||
|
if (isEven) {
|
||||||
|
base32CharIndex = (base32CharIndex << 1) | divideRangeByValue(longitude, lonRange);
|
||||||
|
} else {
|
||||||
|
base32CharIndex = (base32CharIndex << 1) | divideRangeByValue(latitude, latRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
isEven = !isEven;
|
||||||
|
|
||||||
|
if (bit < 4) {
|
||||||
|
bit++;
|
||||||
|
} else {
|
||||||
|
geohash.append(BASE_32.charAt(base32CharIndex));
|
||||||
|
bit = 0;
|
||||||
|
base32CharIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return geohash.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String encodeGeohash(DeviceLocation deviceLocation) {
|
||||||
|
return encodeGeohash(deviceLocation.getLatitude(), deviceLocation.getLongitude());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GeoCoordinate decodeGeohash(String geohash) {
|
||||||
|
double[] latRange = new double[]{-90.0, 90.0};
|
||||||
|
double[] lonRange = new double[]{-180.0, 180.0};
|
||||||
|
boolean isEvenBit = true;
|
||||||
|
|
||||||
|
for (int i = 0; i < geohash.length(); i++) {
|
||||||
|
int base32CharIndex = BASE_32.indexOf(geohash.charAt(i));
|
||||||
|
for (int j = 4; j >= 0; j--) {
|
||||||
|
if (isEvenBit) {
|
||||||
|
divideRangeByBit((base32CharIndex >> j) & 1, lonRange);
|
||||||
|
} else {
|
||||||
|
divideRangeByBit((base32CharIndex >> j) & 1, latRange);
|
||||||
|
}
|
||||||
|
isEvenBit = !isEvenBit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GeoCoordinate coordinates = new GeoCoordinate(middle(latRange),middle(lonRange));
|
||||||
|
return coordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package org.wso2.carbon.device.mgt.core.geo.geoHash.geoHashStrategy;
|
||||||
|
|
||||||
|
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is to decide a length for the geohash prefix
|
||||||
|
* which will be used to group the clusters based on geohash
|
||||||
|
*/
|
||||||
|
public interface GeoHashLengthStrategy {
|
||||||
|
int getGeohashLength(GeoCoordinate southWest, GeoCoordinate northEast, int zoom);
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package org.wso2.carbon.device.mgt.core.geo.geoHash.geoHashStrategy;
|
||||||
|
|
||||||
|
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
|
||||||
|
|
||||||
|
/**A class that will decide the geoHashLength based on the zoom level and
|
||||||
|
* the boundaries of the map**/
|
||||||
|
|
||||||
|
public class ZoomGeoHashLengthStrategy implements GeoHashLengthStrategy{
|
||||||
|
|
||||||
|
private int minGeohashLength = 1;
|
||||||
|
private int maxGeohashLength = 16;
|
||||||
|
private int minZoom = 1;
|
||||||
|
private int maxZoom = 17;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getGeohashLength(GeoCoordinate southWest, GeoCoordinate northEast, int zoom) {
|
||||||
|
double a = minGeohashLength / Math.exp(minZoom / (maxZoom - minZoom) * Math.log(maxGeohashLength / minGeohashLength));
|
||||||
|
double b = Math.log(maxGeohashLength / minGeohashLength) / (maxZoom - minZoom);
|
||||||
|
return (int) Math.max(minGeohashLength, Math.min(a * Math.exp(b * zoom), maxGeohashLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinGeohashLength(int minGeohashLength) {
|
||||||
|
this.minGeohashLength = minGeohashLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxGeohashLength(int maxGeohashLength) {
|
||||||
|
this.maxGeohashLength = maxGeohashLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinZoom(int minZoom) {
|
||||||
|
this.minZoom = minZoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxZoom(int maxZoom) {
|
||||||
|
this.maxZoom = maxZoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinGeohashLength() {
|
||||||
|
return minGeohashLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxGeohashLength() {
|
||||||
|
return maxGeohashLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinZoom() {
|
||||||
|
return minZoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxZoom() {
|
||||||
|
return maxZoom;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.internal;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.osgi.service.component.ComponentContext;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.dao.ArchivalDestinationDAOFactory;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.dao.ArchivalSourceDAOFactory;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.DeviceManagementConfig;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.datasource.DataSourceConfig;
|
||||||
|
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
|
||||||
|
import org.wso2.carbon.device.mgt.core.task.ArchivalTaskManager;
|
||||||
|
import org.wso2.carbon.device.mgt.core.task.impl.ArchivalTaskManagerImpl;
|
||||||
|
import org.wso2.carbon.ntask.core.service.TaskService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @scr.component name="org.wso2.carbon.activity.data.archival" immediate="true"
|
||||||
|
* @scr.reference name="device.ntask.component"
|
||||||
|
* interface="org.wso2.carbon.ntask.core.service.TaskService"
|
||||||
|
* cardinality="1..1"
|
||||||
|
* policy="dynamic"
|
||||||
|
* bind="setTaskService"
|
||||||
|
* unbind="unsetTaskService"
|
||||||
|
* @scr.reference name="org.wso2.carbon.device.manager"
|
||||||
|
* interface="org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService"
|
||||||
|
* cardinality="1..1"
|
||||||
|
* policy="dynamic"
|
||||||
|
* bind="setDeviceManagementService"
|
||||||
|
* unbind="unsetDeviceManagementService"
|
||||||
|
*/
|
||||||
|
public class ActivityDataPurgingServiceComponent {
|
||||||
|
private static Log log = LogFactory.getLog(ActivityDataPurgingServiceComponent.class);
|
||||||
|
|
||||||
|
protected void activate(ComponentContext componentContext) {
|
||||||
|
try {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Initializing activity data archival task manager bundle.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialising data archival configurations */
|
||||||
|
DeviceManagementConfig config =
|
||||||
|
DeviceConfigurationManager.getInstance().getDeviceManagementConfig();
|
||||||
|
|
||||||
|
boolean archivalTaskEnabled = false;
|
||||||
|
boolean purgingTaskEnabled = false;
|
||||||
|
|
||||||
|
if (config.getArchivalConfiguration() != null
|
||||||
|
&& config.getArchivalConfiguration().getArchivalTaskConfiguration() != null){
|
||||||
|
archivalTaskEnabled = config.getArchivalConfiguration().getArchivalTaskConfiguration().isEnabled();
|
||||||
|
purgingTaskEnabled = config.getArchivalConfiguration().getArchivalTaskConfiguration()
|
||||||
|
.getPurgingTaskConfiguration() != null
|
||||||
|
&& config.getArchivalConfiguration()
|
||||||
|
.getArchivalTaskConfiguration().getPurgingTaskConfiguration().isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (archivalTaskEnabled || purgingTaskEnabled) {
|
||||||
|
DataSourceConfig dsConfig = config.getDeviceManagementConfigRepository().getDataSourceConfig();
|
||||||
|
ArchivalSourceDAOFactory.init(dsConfig);
|
||||||
|
DataSourceConfig purgingDSConfig = config.getArchivalConfiguration().getDataSourceConfig();
|
||||||
|
ArchivalDestinationDAOFactory.init(purgingDSConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchivalTaskManager archivalTaskManager = new ArchivalTaskManagerImpl();
|
||||||
|
|
||||||
|
// This will start the data archival task
|
||||||
|
if (archivalTaskEnabled) {
|
||||||
|
archivalTaskManager.scheduleArchivalTask();
|
||||||
|
log.info("Data archival task has been scheduled.");
|
||||||
|
} else {
|
||||||
|
log.warn("Data archival task has been disabled. It is recommended to enable archival task to " +
|
||||||
|
"prune the transactional databases tables time to time if you are using MySQL.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will start the data deletion task.
|
||||||
|
if (purgingTaskEnabled) {
|
||||||
|
archivalTaskManager.scheduleDeletionTask();
|
||||||
|
log.info("Data purging task has been scheduled for archived data.");
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("Error occurred while initializing activity data archival task manager service.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setTaskService(TaskService taskService) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Setting the task service.");
|
||||||
|
}
|
||||||
|
DeviceManagementDataHolder.getInstance().setTaskService(taskService);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void unsetTaskService(TaskService taskService) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Removing the task service.");
|
||||||
|
}
|
||||||
|
DeviceManagementDataHolder.getInstance().setTaskService(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setDeviceManagementService(DeviceManagementProviderService deviceManagementService){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void unsetDeviceManagementService(DeviceManagementProviderService deviceManagementService){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
protected void deactivate(ComponentContext componentContext) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.task;
|
||||||
|
|
||||||
|
public class ArchivalTaskException extends Exception {
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
public String getErrorMessage() {
|
||||||
|
return errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrorMessage(String errorMessage) {
|
||||||
|
this.errorMessage = errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchivalTaskException(String message) {
|
||||||
|
super(message);
|
||||||
|
setErrorMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchivalTaskException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
setErrorMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchivalTaskException(String message, Throwable cause, boolean enableSuppression,
|
||||||
|
boolean writableStackTrace, String errorMessage) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
setErrorMessage(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.task;
|
||||||
|
|
||||||
|
public interface ArchivalTaskManager {
|
||||||
|
|
||||||
|
void scheduleArchivalTask() throws ArchivalTaskException;
|
||||||
|
|
||||||
|
void scheduleDeletionTask() throws ArchivalTaskException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.task.impl;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.ArchivalException;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.ArchivalService;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.ArchivalServiceImpl;
|
||||||
|
import org.wso2.carbon.ntask.core.Task;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
|
public class ArchivalTask implements Task {
|
||||||
|
private static Log log = LogFactory.getLog(ArchivalTask.class);
|
||||||
|
|
||||||
|
private ArchivalService archivalService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProperties(Map<String, String> map) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
this.archivalService = new ArchivalServiceImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
log.info("Executing ArchivalTask at " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()));
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
archivalService.archiveTransactionalRecords();
|
||||||
|
} catch (ArchivalException e) {
|
||||||
|
log.error("An error occurred while running ArchivalTask", e);
|
||||||
|
}
|
||||||
|
long endTime = System.currentTimeMillis();
|
||||||
|
long difference = endTime - startTime;
|
||||||
|
log.info("ArchivalTask completed. Total execution time: " + getDurationBreakdown(difference));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDurationBreakdown(long millis) {
|
||||||
|
if (millis < 0) {
|
||||||
|
throw new IllegalArgumentException("Duration must be greater than zero!");
|
||||||
|
}
|
||||||
|
long days = TimeUnit.MILLISECONDS.toDays(millis);
|
||||||
|
millis -= TimeUnit.DAYS.toMillis(days);
|
||||||
|
long hours = TimeUnit.MILLISECONDS.toHours(millis);
|
||||||
|
millis -= TimeUnit.HOURS.toMillis(hours);
|
||||||
|
long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
|
||||||
|
millis -= TimeUnit.MINUTES.toMillis(minutes);
|
||||||
|
long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder(64);
|
||||||
|
sb.append(days);
|
||||||
|
sb.append(" Days ");
|
||||||
|
sb.append(hours);
|
||||||
|
sb.append(" Hours ");
|
||||||
|
sb.append(minutes);
|
||||||
|
sb.append(" Minutes ");
|
||||||
|
sb.append(seconds);
|
||||||
|
sb.append(" Seconds");
|
||||||
|
|
||||||
|
return (sb.toString());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.task.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||||
|
import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager;
|
||||||
|
import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder;
|
||||||
|
import org.wso2.carbon.device.mgt.core.task.ArchivalTaskException;
|
||||||
|
import org.wso2.carbon.device.mgt.core.task.ArchivalTaskManager;
|
||||||
|
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.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ArchivalTaskManagerImpl implements ArchivalTaskManager {
|
||||||
|
private static final String TASK_TYPE_ARCHIVAL = "DATA_ARCHIVAL";
|
||||||
|
private static final String TASK_TYPE_DELETION = "DATA_DELETION";
|
||||||
|
|
||||||
|
private static final String TASK_NAME_ARCHIVAL = "DATA_ARCHIVAL_TASK";
|
||||||
|
private static final String TASK_NAME_DELETION = "DATA_DELETION_TASK";
|
||||||
|
|
||||||
|
private static final String TENANT_ID = "TENANT_ID";
|
||||||
|
|
||||||
|
private static Log log = LogFactory.getLog(ArchivalTaskManagerImpl.class);
|
||||||
|
|
||||||
|
public void scheduleArchivalTask() throws ArchivalTaskException {
|
||||||
|
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
|
||||||
|
|
||||||
|
try {
|
||||||
|
TaskService taskService = DeviceManagementDataHolder.getInstance().getTaskService();
|
||||||
|
taskService.registerTaskType(TASK_TYPE_ARCHIVAL);
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Data archival task is started for the tenant id " + tenantId);
|
||||||
|
}
|
||||||
|
String taskClazz = DeviceConfigurationManager.getInstance().getDeviceManagementConfig()
|
||||||
|
.getArchivalConfiguration().getArchivalTaskConfiguration().getTaskClazz();
|
||||||
|
String cronExpression = DeviceConfigurationManager.getInstance().getDeviceManagementConfig()
|
||||||
|
.getArchivalConfiguration().getArchivalTaskConfiguration().getCronExpression();
|
||||||
|
|
||||||
|
TaskManager taskManager = taskService.getTaskManager(TASK_TYPE_ARCHIVAL);
|
||||||
|
|
||||||
|
TaskInfo.TriggerInfo triggerInfo = new TaskInfo.TriggerInfo();
|
||||||
|
triggerInfo.setCronExpression(cronExpression);
|
||||||
|
triggerInfo.setRepeatCount(-1);
|
||||||
|
triggerInfo.setDisallowConcurrentExecution(true);
|
||||||
|
|
||||||
|
Map<String, String> properties = new HashMap<>();
|
||||||
|
properties.put(TENANT_ID, String.valueOf(tenantId));
|
||||||
|
|
||||||
|
if (!taskManager.isTaskScheduled(TASK_NAME_ARCHIVAL)) {
|
||||||
|
TaskInfo taskInfo = new TaskInfo(TASK_NAME_ARCHIVAL, taskClazz, properties, triggerInfo);
|
||||||
|
taskManager.registerTask(taskInfo);
|
||||||
|
taskManager.rescheduleTask(taskInfo.getName());
|
||||||
|
} else {
|
||||||
|
throw new ArchivalTaskException("Data archival task is already started for this tenant " +
|
||||||
|
tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (TaskException e) {
|
||||||
|
throw new ArchivalTaskException("Error occurred while creating the task for tenant " + tenantId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scheduleDeletionTask() throws ArchivalTaskException {
|
||||||
|
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
|
||||||
|
try {
|
||||||
|
TaskService taskService = DeviceManagementDataHolder.getInstance().getTaskService();
|
||||||
|
taskService.registerTaskType(TASK_TYPE_DELETION);
|
||||||
|
|
||||||
|
String taskClazz = DeviceConfigurationManager.getInstance().getDeviceManagementConfig()
|
||||||
|
.getArchivalConfiguration().getArchivalTaskConfiguration()
|
||||||
|
.getPurgingTaskConfiguration().getTaskClazz();
|
||||||
|
String cronExpression = DeviceConfigurationManager.getInstance().getDeviceManagementConfig()
|
||||||
|
.getArchivalConfiguration().getArchivalTaskConfiguration()
|
||||||
|
.getPurgingTaskConfiguration().getCronExpression();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Data deletion task is started for the tenant id " + tenantId);
|
||||||
|
}
|
||||||
|
TaskManager taskManager = taskService.getTaskManager(TASK_TYPE_DELETION);
|
||||||
|
|
||||||
|
TaskInfo.TriggerInfo triggerInfo = new TaskInfo.TriggerInfo();
|
||||||
|
triggerInfo.setCronExpression(cronExpression);
|
||||||
|
triggerInfo.setRepeatCount(-1);
|
||||||
|
triggerInfo.setDisallowConcurrentExecution(true);
|
||||||
|
|
||||||
|
Map<String, String> properties = new HashMap<>();
|
||||||
|
properties.put(TENANT_ID, String.valueOf(tenantId));
|
||||||
|
|
||||||
|
if (!taskManager.isTaskScheduled(TASK_NAME_DELETION)) {
|
||||||
|
TaskInfo taskInfo = new TaskInfo(TASK_NAME_DELETION, taskClazz, properties, triggerInfo);
|
||||||
|
taskManager.registerTask(taskInfo);
|
||||||
|
taskManager.rescheduleTask(taskInfo.getName());
|
||||||
|
} else {
|
||||||
|
throw new ArchivalTaskException("Data deletion task is already started for this tenant " +
|
||||||
|
tenantId);
|
||||||
|
}
|
||||||
|
} catch (TaskException e) {
|
||||||
|
throw new ArchivalTaskException("Error occurred while creating the task for tenant " + tenantId, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. 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.mgt.core.task.impl;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.ArchivalException;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.ArchivalService;
|
||||||
|
import org.wso2.carbon.device.mgt.core.archival.ArchivalServiceImpl;
|
||||||
|
import org.wso2.carbon.ntask.core.Task;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ArchivedDataDeletionTask implements Task {
|
||||||
|
|
||||||
|
private static Log log = LogFactory.getLog(ArchivedDataDeletionTask.class);
|
||||||
|
|
||||||
|
private ArchivalService archivalService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProperties(Map<String, String> map) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
this.archivalService = new ArchivalServiceImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
log.info("Executing DataDeletionTask at " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()));
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
try {
|
||||||
|
archivalService.deleteArchivedRecords();
|
||||||
|
} catch (ArchivalException e) {
|
||||||
|
log.error("An error occurred while executing DataDeletionTask", e);
|
||||||
|
}
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long difference = (endTime - startTime) / 1000000 * 1000;
|
||||||
|
log.info("DataDeletionTask completed. Total execution time: " + difference + " seconds");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
{{!
|
||||||
|
Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
|
||||||
|
WSO2 Inc. 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.
|
||||||
|
}}
|
||||||
|
{{unit "cdmf.unit.ui.title" pageTitle="Device Location"}}
|
||||||
|
|
||||||
|
{{#zone "breadcrumbs"}}
|
||||||
|
<li>
|
||||||
|
<a href="{{@app.context}}/">
|
||||||
|
<i class="icon fw fw-home"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{@app.context}}/device-locations">
|
||||||
|
Device Locations
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/zone}}
|
||||||
|
|
||||||
|
{{#zone "content"}}
|
||||||
|
{{unit "cdmf.unit.geo-devices"}}
|
||||||
|
{{/zone}}
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0.0",
|
||||||
|
"uri": "/device-locations",
|
||||||
|
"layout": "cdmf.layout.default"
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
{{!
|
||||||
|
Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
|
||||||
|
WSO2 Inc. 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.
|
||||||
|
}}
|
||||||
|
|
||||||
|
{{#zone "topCss"}}
|
||||||
|
{{css "css/app.css" combine=false}}
|
||||||
|
{{css "css/map.css" combine=false}}
|
||||||
|
{{css "css/leaflet.css" combine=false}}
|
||||||
|
{{css "css/L.Control.Locate.css" combine=false}}
|
||||||
|
{{css "css/MarkerCluster.Default.css" combine=false}}
|
||||||
|
{{css "css/leaflet_fullscreen/leaflet.fullscreen.css" combine=false}}
|
||||||
|
{{css "css/leaflet/leaflet.draw.css" combine=false}}
|
||||||
|
{{css "css/leaflet.awesome-markers.css" combine=false}}
|
||||||
|
{{/zone}}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="map-wrapper">
|
||||||
|
<div id="" style="height: 80vh;">
|
||||||
|
<div id="map"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#zone "bottomJs" }}
|
||||||
|
{{js "js/leaflet/leaflet.js" }}
|
||||||
|
{{js "js/leaflet/leaflet.markercluster.js" }}
|
||||||
|
{{js "js/leaflet/L.Control.Locate.js" }}
|
||||||
|
{{js "js/leaflet/L.Control.Focus.js" }}
|
||||||
|
{{js "js/leaflet/leaflet.groupedlayercontrol.js" }}
|
||||||
|
{{js "js/leaflet/Leaflet.fullscreen.min.js" }}
|
||||||
|
{{js "js/leaflet/Marker.Rotate.js" }}
|
||||||
|
{{js "js/leaflet/leaflet.draw.js" }}
|
||||||
|
{{js "js/leaflet.awesome-markers.js"}}
|
||||||
|
{{js "js/typeahead.bundle.min.js" }}
|
||||||
|
{{js "js/geo_remote.js" }}
|
||||||
|
{{js "js/app.js" }}
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function () {
|
||||||
|
initialLoad(false);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{{/zone}}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0.0"
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/* Compatible with Leaflet 0.7 */
|
||||||
|
|
||||||
|
@import url('font/locate-fa.woff');
|
||||||
|
@import url('css/locate-fa.css');
|
||||||
|
@import url('css/animation.css');
|
||||||
|
|
||||||
|
.leaflet-touch .leaflet-bar-part-single {
|
||||||
|
-webkit-border-radius: 7px 7px 7px 7px;
|
||||||
|
border-radius: 7px 7px 7px 7px;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-control-locate a {
|
||||||
|
font-size: 1.4em;
|
||||||
|
margin-left: 1px;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-control-locate.active a {
|
||||||
|
color: #2074B6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-control-locate.active.following a {
|
||||||
|
color: #FC8428;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-touch .leaflet-control-locate {
|
||||||
|
box-shadow: none;
|
||||||
|
border: 2px solid rgba(0,0,0,0.2);
|
||||||
|
background-clip: padding-box;
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
/* Conditional stylesheet for IE. */
|
||||||
|
@import url('css/locate-fa-ie7.css');
|
||||||
|
|
||||||
|
.leaflet-control-locate {
|
||||||
|
border: 3px solid #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-control-locate a {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-control-locate a:hover {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
.marker-cluster-small {
|
||||||
|
background-color: rgba(181, 226, 140, 0.6);
|
||||||
|
}
|
||||||
|
.marker-cluster-small div {
|
||||||
|
background-color: rgba(110, 204, 57, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.marker-cluster-medium {
|
||||||
|
background-color: rgba(241, 211, 87, 0.6);
|
||||||
|
}
|
||||||
|
.marker-cluster-medium div {
|
||||||
|
background-color: rgba(240, 194, 12, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.marker-cluster-large {
|
||||||
|
background-color: rgba(253, 156, 115, 0.6);
|
||||||
|
}
|
||||||
|
.marker-cluster-large div {
|
||||||
|
background-color: rgba(241, 128, 23, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IE 6-8 fallback colors */
|
||||||
|
.leaflet-oldie .marker-cluster-small {
|
||||||
|
background-color: rgb(181, 226, 140);
|
||||||
|
}
|
||||||
|
.leaflet-oldie .marker-cluster-small div {
|
||||||
|
background-color: rgb(110, 204, 57);
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-oldie .marker-cluster-medium {
|
||||||
|
background-color: rgb(241, 211, 87);
|
||||||
|
}
|
||||||
|
.leaflet-oldie .marker-cluster-medium div {
|
||||||
|
background-color: rgb(240, 194, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-oldie .marker-cluster-large {
|
||||||
|
background-color: rgb(253, 156, 115);
|
||||||
|
}
|
||||||
|
.leaflet-oldie .marker-cluster-large div {
|
||||||
|
background-color: rgb(241, 128, 23);
|
||||||
|
}
|
||||||
|
|
||||||
|
.marker-cluster {
|
||||||
|
background-clip: padding-box;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
.marker-cluster div {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 15px;
|
||||||
|
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
.marker-cluster span {
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
|
||||||
|
-webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||||
|
-moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||||
|
-o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||||
|
transition: transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
input[type="radio"], input[type="checkbox"] {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.map-wrapper{
|
||||||
|
background: #37474f;
|
||||||
|
}
|
||||||
|
#left_side_pannel> .nav > li > a{
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.typeahead {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
#map {
|
||||||
|
width: auto;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
#loading {
|
||||||
|
position: absolute;
|
||||||
|
width: 220px;
|
||||||
|
height: 19px;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
margin: -10px 0 0 -110px;
|
||||||
|
z-index: 20001;
|
||||||
|
}
|
||||||
|
/*.sidebar-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.sidebar-table {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
top: 124px;
|
||||||
|
bottom: 0px;
|
||||||
|
overflow: auto;
|
||||||
|
}*/
|
||||||
|
.leaflet-control-layers label {
|
||||||
|
font-weight: normal;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
.leaflet-control-layers-group-name {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: .2em;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.leaflet-control-layers-group {
|
||||||
|
margin-bottom: .5em;
|
||||||
|
}
|
||||||
|
.leaflet-control-layers-group label {
|
||||||
|
padding-left: .5em;
|
||||||
|
}
|
||||||
|
.table {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tt-dropdown-menu {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 4px 4px 4px 4px;
|
||||||
|
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
||||||
|
margin-top: 4px;
|
||||||
|
padding: 4px 0;
|
||||||
|
width: 100%;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.tt-suggestion {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 3px 10px;
|
||||||
|
}
|
||||||
|
.tt-suggestion.tt-cursor {
|
||||||
|
background-color: #0097CF;
|
||||||
|
color: #FFFFFF;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.tt-suggestion p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.tt-suggestion + .tt-suggestion {
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
.typeahead-header {
|
||||||
|
margin: 0 5px 5px 5px;
|
||||||
|
padding: 3px 0;
|
||||||
|
border-bottom: 2px solid #333;
|
||||||
|
}
|
||||||
|
.has-feedback .form-control-feedback {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
display: block;
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
line-height: 34px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
/*.navbar .navbar-brand {
|
||||||
|
font-size: 18px;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
@media (max-width: 767px){
|
||||||
|
.url-break {
|
||||||
|
word-break: break-all;
|
||||||
|
word-break: break-word;
|
||||||
|
-webkit-hyphens: auto;
|
||||||
|
hyphens: auto;
|
||||||
|
}
|
||||||
|
#sidebar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-geo-alerts{
|
||||||
|
border-radius: 4px;
|
||||||
|
border: none;
|
||||||
|
background-color: white;
|
||||||
|
padding: 5px;
|
||||||
|
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||||
|
width: 200px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-geo-alerts a{
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
!* Print Handling *!
|
||||||
|
@media print {
|
||||||
|
.navbar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.leaflet-control-container {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav > li > a {
|
||||||
|
padding: 25px 15px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav > li > a:hover, .nav > li > a:focus {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
*/
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (C) 2013 Panopta, Andrew Moffat
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -0,0 +1,182 @@
|
|||||||
|
/* WIZARD GENERAL */
|
||||||
|
.wizard {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-dialog {}
|
||||||
|
.wizard-content {}
|
||||||
|
|
||||||
|
.wizard-body {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WIZARD HEADER */
|
||||||
|
.wizard-header {
|
||||||
|
padding: 9px 15px;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
line-height: 35px;
|
||||||
|
display: inline;
|
||||||
|
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||||
|
font-family: inherit;
|
||||||
|
font-weight: bold;
|
||||||
|
text-rendering: optimizelegibility;
|
||||||
|
color: rgb(51, 51, 51);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-subtitle {
|
||||||
|
font-weight:bold;
|
||||||
|
color:#AFAFAF;
|
||||||
|
padding-left:20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* WIZARD NAVIGATION */
|
||||||
|
.wizard-steps {
|
||||||
|
width: 28%;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-bottom-left-radius: 6px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-nav-container {
|
||||||
|
padding-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-nav-list {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-nav-link .glyphicon-chevron-right {
|
||||||
|
float:right;
|
||||||
|
margin-top:12px;
|
||||||
|
margin-right:-6px;
|
||||||
|
opacity:.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.wizard-nav-item.active .glyphicon-chevron-right {
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.wizard-nav-item {
|
||||||
|
line-height:40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-nav-list > li > a {
|
||||||
|
background-color:#f5f5f5;
|
||||||
|
padding:3px 15px 3px 20px;
|
||||||
|
cursor:default;
|
||||||
|
color:#B4B4B4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-nav-list > li > a:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-nav-list > li.already-visited > a.wizard-nav-link {
|
||||||
|
color:#08C;
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-nav-list > li.active > a.wizard-nav-link {
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-nav-item .already-visited .active {
|
||||||
|
background-color:#08C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-nav-list li.active > a {
|
||||||
|
background-color:#08C;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* WIZARD CONTENT */
|
||||||
|
.wizard-body form {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WIZARD PROGRESS BAR */
|
||||||
|
.wizard-progress-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-card-container {
|
||||||
|
margin-left: 28%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WIZARD CARDS */
|
||||||
|
.wizard-error,
|
||||||
|
.wizard-failure,
|
||||||
|
.wizard-success,
|
||||||
|
.wizard-loading,
|
||||||
|
.wizard-card {
|
||||||
|
border-top: 1px solid #EEE;
|
||||||
|
display:none;
|
||||||
|
padding:35px;
|
||||||
|
padding-top:20px;
|
||||||
|
overflow-y:auto;
|
||||||
|
|
||||||
|
/*
|
||||||
|
position:relative;
|
||||||
|
height:300px;
|
||||||
|
margin-right: 5px;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-card-overlay {
|
||||||
|
overflow-y: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-card > h3 {
|
||||||
|
margin-top:0;
|
||||||
|
margin-bottom:20px;
|
||||||
|
font-size:21px;
|
||||||
|
line-height:40px;
|
||||||
|
font-weight:normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WIZARD FOOTER */
|
||||||
|
.wizard-footer {
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-buttons-container {
|
||||||
|
padding:20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-cancel {
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inner Card */
|
||||||
|
.wizard-input-section {
|
||||||
|
margin-bottom:20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-dialog .popover.error-popover {
|
||||||
|
background-color:#F2DEDE;
|
||||||
|
color:#B94A48;
|
||||||
|
border-color:#953B39;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-dialog .popover.error-popover .arrow::after {
|
||||||
|
border-right-color:#F2DEDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-dialog .popover.error-popover .popover-title {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-dialog .popover.error-popover .arrow {
|
||||||
|
border-right-color:#953B39;
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
Animation example, for spinners
|
||||||
|
*/
|
||||||
|
.animate-spin:before {
|
||||||
|
-moz-animation: spin 2s infinite linear;
|
||||||
|
-o-animation: spin 2s infinite linear;
|
||||||
|
-webkit-animation: spin 2s infinite linear;
|
||||||
|
animation: spin 2s infinite linear;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
@-moz-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-moz-transform: rotate(359deg);
|
||||||
|
-o-transform: rotate(359deg);
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-moz-transform: rotate(359deg);
|
||||||
|
-o-transform: rotate(359deg);
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-o-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-moz-transform: rotate(359deg);
|
||||||
|
-o-transform: rotate(359deg);
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-ms-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-moz-transform: rotate(359deg);
|
||||||
|
-o-transform: rotate(359deg);
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-moz-transform: rotate(359deg);
|
||||||
|
-o-transform: rotate(359deg);
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
.icon-location:before { content: '\e802'; } /* '' */
|
||||||
|
.icon-direction:before { content: '\e800'; } /* '' */
|
||||||
|
.icon-spinner:before { content: '\e801'; } /* '' */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue