Java tutorial
/* * 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; } }