com.htmlhifive.sync.service.SyncResourceProcessor.java Source code

Java tutorial

Introduction

Here is the source code for com.htmlhifive.sync.service.SyncResourceProcessor.java

Source

/*
 * Copyright (C) 2012-2013 NS Solutions Corporation
 *
 * Licensed 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 com.htmlhifive.sync.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import com.htmlhifive.resourcefw.exception.AbstractResourceException;
import com.htmlhifive.resourcefw.message.MessageSource;
import com.htmlhifive.resourcefw.message.RequestMessage;
import com.htmlhifive.resourcefw.message.RequestMessageContainer;
import com.htmlhifive.resourcefw.message.ResponseMessage;
import com.htmlhifive.resourcefw.message.ResponseMessageContainer;
import com.htmlhifive.resourcefw.resource.ResourceMethodInvoker;
import com.htmlhifive.resourcefw.service.DefaultResourceProcessor;
import com.htmlhifive.resourcefw.util.ResourcePathUtil;
import com.htmlhifive.sync.config.DownloadControlType;
import com.htmlhifive.sync.config.SyncConfigurationParameter;
import com.htmlhifive.sync.config.UploadControlType;
import com.htmlhifive.sync.exception.SyncUploadDuplicatedException;
import com.htmlhifive.sync.resource.SyncResource;
import com.htmlhifive.sync.resource.Synchronizer;
import com.htmlhifive.sync.resource.common.ResourceItemCommonData;
import com.htmlhifive.sync.resource.common.ResourceItemCommonDataId;
import com.htmlhifive.sync.resource.common.SyncAction;

/**
 * sync??resource framework?.<br>
 * ??????????????????.<br>
 * ???????????.
 *
 * @author kishigam
 */
public class SyncResourceProcessor extends DefaultResourceProcessor {

    private static final Logger LOGGER = Logger.getLogger(SyncResourceProcessor.class);

    /**
     * ???????
     */
    private Synchronizer synchronizer;

    /**
     * sync?
     */
    private SyncConfigurationParameter syncConfigurationParameter;

    /**
     * sync??????.
     */
    @Autowired
    private SyncRequestCommonDataRepository syncRequestCommonDataRepository;

    /**
     * HttpServletRequest ?????
     */
    @Autowired
    private HttpServletRequest httpServletRequest;

    /**
     * ??????????????????.
     */
    @Override
    protected void preProcess(RequestMessageContainer requestMessages) {

        String requestPathStr = extractRequestPath(requestMessages);
        String httpMethod = httpServletRequest.getMethod();

        boolean uploadRequest = isUploadRequest(requestPathStr);
        boolean downloadRequest = isDownloadRequest(requestPathStr);
        boolean syncByHttpMethodRequest = isSyncByHttpMethodRequest(requestPathStr);

        if (syncByHttpMethodRequest) {
            // FIXME ??????HTTP??/??????
            if (httpMethod.equals("GET")) {
                downloadRequest = true;
            } else if (httpMethod.equals("POST") || httpMethod.equals("PUT") || httpMethod.equals("DELETE")) {
                uploadRequest = true;
            }
        }

        // sync????????
        if (!(uploadRequest || downloadRequest)) {
            return;
        }

        // URL?sync?
        overwritePath(requestMessages, requestPathStr);

        // ??ID???
        extractResourceItemCommonId(requestMessages);

        String action = null;
        if (uploadRequest) {
            SyncRequestCommonData currentRequest = (SyncRequestCommonData) requestMessages
                    .getContextData(syncConfigurationParameter.REQUEST_COMMON_DATA);

            // ??
            // ???????????????????
            if (currentRequest.hasLastUploadTime()) {
                checkDuplicateUpload(currentRequest, requestMessages);
            }

            // SyncAction????????????
            // ????????
            setSyncAction(requestMessages, httpMethod);

            // ??
            try {
                processUploadControl(requestMessages);
            } catch (AbstractResourceException e) {
                LOGGER.info("[syncfw]Resource sync upload processing is terminated by exception, status : "
                        + e.getErrorStatus() + " ,detail : " + e.getMessage());
            }

            action = syncConfigurationParameter.ACTION_FOR_UPLOAD;
        }

        if (downloadRequest) {

            // ????????
            try {
                processDownloadControl(requestMessages);
            } catch (AbstractResourceException e) {
                LOGGER.info("[syncfw]Resource sync download processing is terminated by exception, status : "
                        + e.getErrorStatus() + " ,detail : " + e.getMessage());
            }

            action = syncConfigurationParameter.ACTION_FOR_DOWNLOAD;
        }

        // ???
        for (RequestMessage requestMessage : requestMessages.getMessages()) {
            requestMessage.put(getMessageMetadata().ACTION, action, MessageSource.PROCESSOR);
        }
    }

    /**
     * ??????sync?(/)?????????.<br/>
     * ???(??????)???.
     *
     * @param requestMessages
     * @return ????
     */
    private String extractRequestPath(RequestMessageContainer requestMessages) {

        if (requestMessages.isMultiplexed()) {
            return (String) requestMessages.getContextData(getMessageMetadata().REQUEST_PATH);
        }

        return (String) requestMessages.getMessages().get(0).get(getMessageMetadata().REQUEST_PATH);
    }

    /**
     * sync?(/)??????????.<br/>
     * ???(??????)???.
     *
     * @param requestMessages
     * @return ????
     */
    private String[] overwritePath(RequestMessageContainer requestMessages, String requestPathStr) {

        String[] result;

        if (requestMessages.isMultiplexed()) {

            result = ResourcePathUtil.down(requestPathStr);
            requestMessages.putContextData(getMessageMetadata().REQUEST_PATH, result[1], MessageSource.PROCESSOR);

        } else {

            RequestMessage requestMessage = requestMessages.getMessages().get(0);

            result = ResourcePathUtil.down(requestPathStr);
            requestMessage.put(getMessageMetadata().REQUEST_PATH, result[1], MessageSource.PROCESSOR);
        }

        return result;
    }

    /**
     * URL?sync??????true???.
     *
     * @param requestPathStr URL
     * @return sync???true
     */
    private boolean isUploadRequest(String requestPathStr) {

        String[] pathStr = ResourcePathUtil.down(requestPathStr);

        return pathStr[0].equals(syncConfigurationParameter.URL_PATH_UPLOAD);
    }

    /**
     * URL?sync??????true???.
     *
     * @param requestPathStr URL
     * @return sync???true
     */
    private boolean isDownloadRequest(String requestPathStr) {

        String[] pathStr = ResourcePathUtil.down(requestPathStr);

        return pathStr[0].equals(syncConfigurationParameter.URL_PATH_DOWNLOAD);
    }

    /**
     * URL?sync??????true???.
     *
     * @param requestPathStr URL
     * @return sync???true
     */
    private boolean isSyncByHttpMethodRequest(String requestPathStr) {
        String[] pathStr = ResourcePathUtil.down(requestPathStr);
        return pathStr[0].equals(syncConfigurationParameter.URL_PATH_SYNC_BY_HTTP_METHODS);
    }

    /**
     * ??syncID???????.<br/>
     * syncID?????????????.
     *
     * @param requestMessages 
     */
    private void extractResourceItemCommonId(RequestMessageContainer requestMessages) {

        for (RequestMessage requestMessage : requestMessages.getMessages()) {

            String resourceName = ResourcePathUtil.down((String) requestMessage.getPath())[0];
            String resourceItemId = (String) requestMessage.get(syncConfigurationParameter.RESOURCE_ITEM_ID);

            ResourceItemCommonDataId commonDataId = new ResourceItemCommonDataId(resourceName, resourceItemId);
            requestMessage.put(syncConfigurationParameter.RESOURCE_ITEM_COMMON_DATA_ID, commonDataId,
                    MessageSource.PROCESSOR);
        }
    }

    /**
     * ???sync??????.<br/>
     * ??????????????.<br/>
     * ??????????????.<br/>
     * ???????????????????????????{@link SyncUploadDuplicatedException
     * SyncUploadDuplicatedException}???.
     *
     * @param currentRequest sync
     * @param requestMessages 
     */
    private void checkDuplicateUpload(SyncRequestCommonData currentRequest,
            RequestMessageContainer requestMessages) {

        SyncRequestCommonData lastUploadRequest = syncRequestCommonDataRepository
                .findOne(currentRequest.getStorageId());

        // ?(??????)?????
        // ????????????(?????)??????????
        if (lastUploadRequest != null && !currentRequest.isLaterUploadThan(lastUploadRequest)) {

            LOGGER.info(new StringBuilder().append("[syncfw] duplicate uploading detected. storageId : ")
                    .append(currentRequest.getStorageId()).append(", lastUpdateTime : ")
                    .append(currentRequest.getLastUploadTime()).toString());

            ResponseMessageContainer responseMessages = new ResponseMessageContainer(
                    requestMessages.isMultiplexed());
            responseMessages.putContextData(syncConfigurationParameter.REQUEST_COMMON_DATA, lastUploadRequest,
                    MessageSource.PROCESSOR);

            throw new SyncUploadDuplicatedException(responseMessages);

        }

        // ?
        syncRequestCommonDataRepository.save(currentRequest);
    }

    /**
     * ?????.<br/>
     * sync?????????.
     *
     * @param requestMessages 
     * @throws AbstractResourceException
     */
    private void processUploadControl(RequestMessageContainer requestMessages) throws AbstractResourceException {

        UploadControlType controlType = UploadControlType.valueOf(syncConfigurationParameter.UPLOAD_CONTROL_TYPE);

        if (controlType == UploadControlType.NONE) {
            return;
        }

        MultiValueMap<ResourceItemCommonDataId, RequestMessage> messageMap = new LinkedMultiValueMap<>();
        for (RequestMessage requestMessage : requestMessages.getMessages()) {
            ResourceItemCommonDataId resourceItemCommonDataId = (ResourceItemCommonDataId) requestMessage
                    .get(syncConfigurationParameter.RESOURCE_ITEM_COMMON_DATA_ID);
            messageMap.add(resourceItemCommonDataId, requestMessage);
        }

        // ID?
        List<ResourceItemCommonDataId> commonDataIdList = new ArrayList<>(messageMap.keySet());
        Collections.sort(commonDataIdList);

        switch (controlType) {
        case SORT:

            // Container?Message???
            List<RequestMessage> sorted = new ArrayList<>();
            for (ResourceItemCommonDataId itemCommonDataId : commonDataIdList) {
                List<RequestMessage> messagesForId = messageMap.get(itemCommonDataId);
                for (RequestMessage message : messagesForId) {
                    sorted.add(message);
                }
            }
            requestMessages.setMessages(sorted);

            break;

        case LOCK:

            // ????
            for (ResourceItemCommonDataId itemCommonDataId : commonDataIdList) {
                List<RequestMessage> messagesForId = messageMap.get(itemCommonDataId);
                for (RequestMessage message : messagesForId) {

                    // ??
                    ResourceMethodInvoker resourceMethod = getResourceManager().getResourceMethodByName(
                            itemCommonDataId.getResourceName(), syncConfigurationParameter.ACTION_FOR_GETFORUPDATE,
                            message);
                    applyDefaultSynchronizer(resourceMethod);

                    // ???
                    // ????????
                    @SuppressWarnings("unchecked")
                    List<ResourceItemCommonData> got = (List<ResourceItemCommonData>) resourceMethod
                            .invoke(message);
                    message.put(syncConfigurationParameter.RESOURCE_ITEM_COMMON_DATA, got);
                }
            }

            break;

        default:
            break;

        }
    }

    /**
     * ?????.<br/>
     * sync?????????.
     *
     * @param requestMessages
     * @throws AbstractResourceException
     */
    private void processDownloadControl(RequestMessageContainer requestMessages) throws AbstractResourceException {

        DownloadControlType controlType = DownloadControlType
                .valueOf(syncConfigurationParameter.DOWNLOAD_CONTROL_TYPE);

        switch (controlType) {

        // LOCK???????
        case LOCK:

            MultiValueMap<ResourceItemCommonDataId, RequestMessage> messageMap = new LinkedMultiValueMap<>();
            for (RequestMessage requestMessage : requestMessages.getMessages()) {
                ResourceItemCommonDataId resourceItemCommonDataId = (ResourceItemCommonDataId) requestMessage
                        .get(syncConfigurationParameter.RESOURCE_ITEM_COMMON_DATA_ID);
                messageMap.add(resourceItemCommonDataId, requestMessage);
            }
            List<ResourceItemCommonDataId> commonDataIdList = new ArrayList<>(messageMap.keySet());
            Collections.sort(commonDataIdList);

            for (ResourceItemCommonDataId itemCommonDataId : commonDataIdList) {

                List<RequestMessage> messagesForId = messageMap.get(itemCommonDataId);
                for (RequestMessage message : messagesForId) {

                    // ??
                    ResourceMethodInvoker resourceMethod = getResourceManager().getResourceMethodByName(
                            itemCommonDataId.getResourceName(), syncConfigurationParameter.ACTION_FOR_GETFORUPDATE,
                            message);
                    applyDefaultSynchronizer(resourceMethod);

                    // ???
                    @SuppressWarnings("unchecked")
                    List<ResourceItemCommonData> got = (List<ResourceItemCommonData>) resourceMethod
                            .invoke(message);
                    message.put(syncConfigurationParameter.RESOURCE_ITEM_COMMON_DATA, got);
                }
            }

        case NONE:
        default:
            break;
        }
    }

    /**
     * ????????????Synchronizer???.<br/>
     */
    @Override
    protected ResponseMessage processMessage(ResourceMethodInvoker resourceMethod, RequestMessage requestMessage)
            throws AbstractResourceException {

        applyDefaultSynchronizer(resourceMethod);
        return super.processMessage(resourceMethod, requestMessage);
    }

    /**
     * ?sync???Synchronizer???????????.
     *
     * @param resourceMethod 
     */
    private void applyDefaultSynchronizer(ResourceMethodInvoker resourceMethod) {

        Object resource = resourceMethod.getResource();
        if (resource instanceof SyncResource) {
            SyncResource syncResource = (SyncResource) resource;
            if (syncResource.getSynchronizer() == null) {
                syncResource.setSynchronizer(this.synchronizer);
            }
        }
    }

    /**
     *
     */
    private void setSyncAction(RequestMessageContainer requestMessages, String httpMethods) {
        for (RequestMessage mes : requestMessages.getMessages()) {
            // syncAction??
            String syncActionStr = (String) mes.get(syncConfigurationParameter.SYNC_ACTION);
            // ???????????
            if (SyncAction.isSyncAction(syncActionStr)) {
                return;
            }

            // 
            switch (httpMethods) {
            case "PUT":
                mes.put(syncConfigurationParameter.SYNC_ACTION, SyncAction.UPDATE.name());
                break;
            case "DELETE":
                mes.put(syncConfigurationParameter.SYNC_ACTION, SyncAction.DELETE.name());
                break;
            default:
                break;
            }
        }
    }

    /**
     * ???????ID??????????????.
     *
     * @param requestMessages 
     * @param responseMessages ?
     */
    @Override
    protected void postProcess(RequestMessageContainer requestMessages, ResponseMessageContainer responseMessages) {

        // ID??????
        SyncRequestCommonData requestCommon = (SyncRequestCommonData) requestMessages
                .getContextData(syncConfigurationParameter.REQUEST_COMMON_DATA);
        responseMessages.putContextData(syncConfigurationParameter.STORAGE_ID, requestCommon.getStorageId(),
                MessageSource.PROCESSOR);

        // ???????(????)
        Long syncTime = requestCommon.getSyncTime();

        // ??preProcess?download or notputContextData???????
        String requestedAction = (String) requestMessages.getMessages().get(0).get(getMessageMetadata().ACTION);
        if (requestedAction.equals(syncConfigurationParameter.ACTION_FOR_DOWNLOAD)) {

            // ???????
            syncTime -= Long.valueOf(syncConfigurationParameter.BUFFER_TIME_FOR_DOWNLOAD);
        }

        responseMessages.putContextData(syncConfigurationParameter.SYNC_TIME, syncTime.toString(),
                MessageSource.PROCESSOR);
    }

    /**
     * @return the synchronizer
     */
    protected Synchronizer getSynchronizer() {
        return synchronizer;
    }

    /**
     * @param synchronizer the synchronizer to set
     */
    public void setSynchronizer(Synchronizer synchronizer) {
        this.synchronizer = synchronizer;
    }

    /**
     * @return the syncConfigurationParameter
     */
    protected SyncConfigurationParameter getSyncConfigurationParameter() {
        return syncConfigurationParameter;
    }

    /**
     * @param syncConfigurationParameter the syncConfigurationParameter to set
     */
    public void setSyncConfigurationParameter(SyncConfigurationParameter syncConfigurationParameter) {
        this.syncConfigurationParameter = syncConfigurationParameter;
    }

    /**
     * @return the syncRequestCommonDataRepository
     */
    protected SyncRequestCommonDataRepository getSyncRequestCommonDataRepository() {
        return syncRequestCommonDataRepository;
    }

    /**
     * @param syncRequestCommonDataRepository the syncRequestCommonDataRepository to set
     */
    public void setSyncRequestCommonDataRepository(
            SyncRequestCommonDataRepository syncRequestCommonDataRepository) {
        this.syncRequestCommonDataRepository = syncRequestCommonDataRepository;
    }
}