/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.sync.engine.document.library.handler;
import com.fasterxml.jackson.databind.JsonNode;
import com.liferay.sync.engine.document.library.event.Event;
import com.liferay.sync.engine.file.system.Watcher;
import com.liferay.sync.engine.file.system.util.WatcherManager;
import com.liferay.sync.engine.model.SyncAccount;
import com.liferay.sync.engine.model.SyncFile;
import com.liferay.sync.engine.service.SyncAccountService;
import com.liferay.sync.engine.service.SyncFileService;
import com.liferay.sync.engine.session.Session;
import com.liferay.sync.engine.session.SessionManager;
import com.liferay.sync.engine.util.ConnectionRetryUtil;
import com.liferay.sync.engine.util.FileUtil;
import com.liferay.sync.engine.util.JSONUtil;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Shinn Lok
*/
public class BaseJSONHandler extends BaseHandler {
public BaseJSONHandler(Event event) {
super(event);
}
@Override
public String getException(String response) {
String exception = null;
JsonNode responseJsonNode = null;
try {
response = StringEscapeUtils.unescapeJava(response);
response = response.replaceAll("\n", "\\n");
responseJsonNode = JSONUtil.readTree(response);
}
catch (Exception e) {
return "";
}
JsonNode errorJsonNode = responseJsonNode.get("error");
if (errorJsonNode == null) {
JsonNode exceptionJsonNode = responseJsonNode.get("exception");
if (exceptionJsonNode == null) {
return "";
}
exception = exceptionJsonNode.asText();
if (exception.startsWith("No JSON web service action")) {
return "NoSuchJSONWebServiceException";
}
}
if (exception == null) {
JsonNode typeJsonNode = null;
JsonNode rootCauseJsonNode = responseJsonNode.get("rootCause");
if (rootCauseJsonNode != null) {
typeJsonNode = rootCauseJsonNode.get("type");
}
else {
typeJsonNode = errorJsonNode.get("type");
}
exception = typeJsonNode.asText();
}
if (exception.equals("java.lang.RuntimeException")) {
JsonNode messageJsonNode = null;
if (errorJsonNode != null) {
messageJsonNode = errorJsonNode.get("message");
}
else {
messageJsonNode = responseJsonNode.get("message");
}
String message = messageJsonNode.asText();
if (message.startsWith("No JSON web service action")) {
return "NoSuchJSONWebServiceException";
}
}
return exception;
}
@Override
public boolean handlePortalException(String exception) throws Exception {
if (exception.isEmpty()) {
return false;
}
String innerException = "";
if (exception.contains("$")) {
String[] exceptionParts = exception.split("\\$");
exception = exceptionParts[0];
innerException = exceptionParts[1];
}
boolean retryInProgress = ConnectionRetryUtil.retryInProgress(
getSyncAccountId());
if (!retryInProgress && _logger.isDebugEnabled()) {
_logger.debug("Handling exception {}", exception);
}
if (exception.equals("Authenticated access required") ||
exception.equals("java.lang.SecurityException")) {
throw new HttpResponseException(
HttpStatus.SC_UNAUTHORIZED, "Authenticated access required");
}
else if (exception.endsWith("DuplicateLockException")) {
SyncFile syncFile = getLocalSyncFile();
if (syncFile == null) {
return true;
}
syncFile.setState(SyncFile.STATE_ERROR);
syncFile.setUiEvent(SyncFile.UI_EVENT_DUPLICATE_LOCK);
SyncFileService.update(syncFile);
}
else if (exception.endsWith("FileExtensionException")) {
SyncFile syncFile = getLocalSyncFile();
if (syncFile == null) {
return true;
}
syncFile.setState(SyncFile.STATE_ERROR);
syncFile.setUiEvent(SyncFile.UI_EVENT_INVALID_FILE_EXTENSION);
SyncFileService.update(syncFile);
}
else if (exception.endsWith("FileNameException") ||
exception.endsWith("FolderNameException")) {
SyncFile syncFile = getLocalSyncFile();
if (syncFile == null) {
return true;
}
syncFile.setState(SyncFile.STATE_ERROR);
syncFile.setUiEvent(SyncFile.UI_EVENT_INVALID_FILE_NAME);
SyncFileService.update(syncFile);
}
else if (exception.equals("java.lang.OutOfMemoryError")) {
retryServerConnection(SyncAccount.UI_EVENT_CONNECTION_EXCEPTION);
}
else if (exception.endsWith("NoSuchFileEntryException") ||
exception.endsWith("NoSuchFolderException")) {
SyncFile syncFile = getLocalSyncFile();
if (syncFile == null) {
return true;
}
Path filePath = Paths.get(syncFile.getFilePathName());
if (FileUtil.exists(filePath)) {
Watcher watcher = WatcherManager.getWatcher(getSyncAccountId());
watcher.addDeletedFilePathName(syncFile.getFilePathName());
FileUtil.deleteFile(filePath);
}
SyncFileService.deleteSyncFile(syncFile, false);
}
else if (exception.endsWith("NoSuchJSONWebServiceException")) {
retryServerConnection(SyncAccount.UI_EVENT_SYNC_WEB_MISSING);
}
else if (exception.endsWith("PrincipalException")) {
SyncFile syncFile = getLocalSyncFile();
if (syncFile == null) {
return true;
}
SyncFileService.setStatuses(
syncFile, SyncFile.STATE_ERROR,
SyncFile.UI_EVENT_INVALID_PERMISSIONS);
}
else if (exception.endsWith("SyncClientMinBuildException")) {
retryServerConnection(
SyncAccount.UI_EVENT_MIN_BUILD_REQUIREMENT_FAILED);
}
else if (exception.endsWith("SyncDeviceActiveException")) {
retryServerConnection(SyncAccount.UI_EVENT_SYNC_ACCOUNT_NOT_ACTIVE);
}
else if (exception.endsWith("SyncDeviceWipeException")) {
if (_logger.isDebugEnabled()) {
_logger.debug("Wiping Sync account {}", getSyncAccountId());
}
SyncAccount syncAccount = SyncAccountService.fetchSyncAccount(
getSyncAccountId());
syncAccount.setUiEvent(SyncAccount.UI_EVENT_SYNC_ACCOUNT_WIPED);
SyncAccountService.update(syncAccount);
SyncAccountService.deleteSyncAccount(getSyncAccountId(), false);
}
else if (exception.endsWith("SyncServicesUnavailableException")) {
retryServerConnection(
SyncAccount.UI_EVENT_SYNC_SERVICES_NOT_ACTIVE);
}
else if (exception.endsWith("SyncSiteUnavailableException")) {
handleSiteDeactivatedException();
}
else if (exception.endsWith("UploadException") ||
innerException.equals("SizeLimitExceededException")) {
SyncFile syncFile = getLocalSyncFile();
if ((syncFile == null) || syncFile.isSystem()) {
return true;
}
syncFile.setState(SyncFile.STATE_ERROR);
syncFile.setUiEvent(SyncFile.UI_EVENT_EXCEEDED_SIZE_LIMIT);
SyncFileService.update(syncFile);
}
else {
if (retryInProgress && _logger.isDebugEnabled()) {
_logger.debug("Handling exception {}", exception);
}
SyncFile syncFile = getLocalSyncFile();
if ((syncFile == null) || syncFile.isSystem()) {
return true;
}
syncFile.setState(SyncFile.STATE_ERROR);
syncFile.setUiEvent(SyncFile.UI_EVENT_NONE);
SyncFileService.update(syncFile);
}
return true;
}
@Override
public Void handleResponse(HttpResponse httpResponse) {
try {
if (isEventCancelled()) {
return null;
}
StatusLine statusLine = httpResponse.getStatusLine();
if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
String response = getResponseString(httpResponse);
if (handlePortalException(getException(response))) {
return null;
}
_logger.error("Status code {}", statusLine.getStatusCode());
throw new HttpResponseException(
statusLine.getStatusCode(), statusLine.getReasonPhrase());
}
doHandleResponse(httpResponse);
}
catch (Exception e) {
handleException(e);
}
finally {
processFinally();
removeEvent();
}
return null;
}
@Override
protected void doHandleResponse(HttpResponse httpResponse)
throws Exception {
Header header = httpResponse.getFirstHeader("Sync-JWT");
if (header != null) {
Session session = SessionManager.getSession(getSyncAccountId());
session.addHeader("Sync-JWT", header.getValue());
}
String response = getResponseString(httpResponse);
if (handlePortalException(getException(response))) {
return;
}
if (_logger.isTraceEnabled()) {
logResponse(response);
}
processResponse(response);
}
protected String getResponseString(HttpResponse httpResponse)
throws Exception {
HttpEntity httpEntity = httpResponse.getEntity();
return EntityUtils.toString(httpEntity);
}
protected void logResponse(String response) {
Class<?> clazz = getClass();
_logger.trace(
"Handling response {} {}", clazz.getSimpleName(), response);
}
private static final Logger _logger = LoggerFactory.getLogger(
BaseJSONHandler.class);
}