/**
* Copyright 2008-2016 Qualogy Solutions B.V.
*
* 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.qualogy.qafe.gwt.server;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Logger;
import javax.servlet.http.Cookie;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang.time.StopWatch;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.qualogy.qafe.bind.core.application.ApplicationContext;
import com.qualogy.qafe.bind.core.application.ApplicationIdentifier;
import com.qualogy.qafe.bind.core.application.Configuration;
import com.qualogy.qafe.core.application.ApplicationCluster;
import com.qualogy.qafe.core.datastore.ApplicationLocalStore;
import com.qualogy.qafe.core.i18n.MessagesHandler;
import com.qualogy.qafe.gwt.client.exception.GWTApplicationStoreException;
import com.qualogy.qafe.gwt.client.exception.GWTServiceException;
import com.qualogy.qafe.gwt.client.service.RPCService;
import com.qualogy.qafe.gwt.client.util.SerializableWhitelist;
import com.qualogy.qafe.gwt.client.vo.data.EventDataGVO;
import com.qualogy.qafe.gwt.client.vo.data.EventItemDataGVO;
import com.qualogy.qafe.gwt.client.vo.data.GDataObject;
import com.qualogy.qafe.gwt.client.vo.data.GEventItemDataObject;
import com.qualogy.qafe.gwt.client.vo.data.InitState;
import com.qualogy.qafe.gwt.client.vo.functions.DataContainerGVO;
import com.qualogy.qafe.gwt.client.vo.ui.UIGVO;
import com.qualogy.qafe.gwt.client.vo.ui.UIVOCluster;
import com.qualogy.qafe.gwt.server.event.assembler.SetValueBuiltInRenderer;
import com.qualogy.qafe.gwt.server.helper.DatagridExportHelper;
import com.qualogy.qafe.gwt.server.processor.EventItemProcessor;
import com.qualogy.qafe.gwt.server.processor.EventProcessor;
import com.qualogy.qafe.gwt.server.processor.impl.EventItemProcessorImpl;
import com.qualogy.qafe.gwt.server.processor.impl.EventProcessorImpl;
import com.qualogy.qafe.gwt.server.service.UIService;
import com.qualogy.qafe.gwt.server.service.impl.UIServiceImpl;
import com.qualogy.qafe.presentation.io.ApplicationClusterUtil;
import com.qualogy.qafe.util.ExceptionHelper;
import com.qualogy.qafe.web.ContextLoader;
import com.qualogy.qafe.web.ContextLoaderHelper;
import com.qualogy.qafe.web.UploadService;
import com.qualogy.qafe.web.css.util.CssProvider;
import com.qualogy.qafe.web.util.DatagridStorageHelper;
import com.qualogy.qafe.web.util.MessageUtil;
import com.qualogy.qafe.web.util.SessionContainer;
import com.qualogy.qafe.web.util.UserAgentUtil;
/**
* @author rjankie
*
*/
public class RPCServiceImpl
extends RemoteServiceServlet implements RPCService {
public final static Logger logger = Logger.getLogger(RPCServiceImpl.class.getName());
private static final long serialVersionUID = 3988869926326800260L;
private UIService service = new UIServiceImpl();
private EventProcessor eventProcessor = new EventProcessorImpl();
/**
* Write the serialized response out to stdout. This is a very unusual thing
* to do, but it allows us to create a static file version of the response
* without deploying a servlet.
*/
protected void onAfterResponseSerialized(String serializedResponse) {
logger.fine(serializedResponse);
}
protected GWTServiceException handleException(Throwable e) {
GWTServiceException gwtE = null;
if (e != null) {
Throwable throwable = ExceptionUtils.getRootCause(e);
if (throwable == null) { // fallback if no rootCause could be found!
throwable = e;
}
gwtE = new GWTServiceException(throwable.getMessage(), throwable);
String detailedMessage = ExceptionHelper.printStackTrace(e);
gwtE.setDetailedMessage(detailedMessage);
} else { // fallback if exception somehow is null
gwtE = new GWTServiceException("Unexpected error occured -" + MessageUtil.SIMPLE_DATE_FORMAT.format(new Date()), (Throwable) null);
gwtE.setDetailedMessage("Unexpected error occured");
}
return gwtE;
}
public UIVOCluster reload(Map<String,String> parameters) throws GWTServiceException {
UIVOCluster cluster = null;
try {
ContextLoader contextLoader = (ContextLoader) getServletContext().getAttribute("contextloader");
contextLoader.init(getServletContext());
MessagesHandler.clear();
String css = CssProvider.getInstance().generateTypedCSS("gwt", null);
service.clear();
cluster = getUISFromApplicationContext(parameters);
cluster.setCss(css);
} catch (Exception e) {
throw handleException(e);
}
return cluster;
}
public UIVOCluster activate(Map<String,String> parameters) throws GWTServiceException {
return getUISFromApplicationContext(parameters);
}
public UIVOCluster getUISFromApplicationContext(Map<String,String> parameters) throws GWTServiceException {
if (getServletContext().getAttribute("init_failure") != null) {
Throwable throwable = (Throwable) getServletContext().getAttribute("init_failure");
getServletContext().removeAttribute("init_failure");
getServletContext().removeAttribute("init_failure_message");
throw handleException(throwable);
} else {
try {
Iterator<ApplicationIdentifier> contextItr = ApplicationCluster.getInstance().keysIterator();
String appId = null;
String windowSession = null;
UIVOCluster cluster = new UIVOCluster();
cluster.setExternalProperties(ApplicationClusterUtil.getExternalProperties());
cluster.setDebugMode(ContextLoaderHelper.isDebugMode());
cluster.setShowLog(ContextLoaderHelper.showLog());
cluster.setGlobalDateFormat(ApplicationClusterUtil.getGlobalDateFormat());
cluster.setReloadable(ContextLoaderHelper.isReloadable(getThreadLocalRequest()));
cluster.setUseDockMode(ContextLoaderHelper.isDockMode());
cluster.setClientSideEventEnabled(ApplicationCluster.getInstance().isClientSideEventEnabled());
UIGVO uiGVO = service.getSystemApplication(ApplicationCluster.getInstance().getSystemApplicationContext(), appId, windowSession, getLocale(),parameters);
cluster.setSystemMenuApplication(uiGVO);
List<UIGVO> gvoList = new ArrayList<UIGVO>();
StopWatch stopWatch = new StopWatch();
while (contextItr.hasNext()) {
ApplicationIdentifier key = contextItr.next();
if (!ApplicationClusterUtil.isSystemApplication(key)) {
stopWatch.start();
UIGVO uigvo = null;
ApplicationContext context = ApplicationCluster.getInstance().get(key);
if(context.getLoadException() == null) {
try {
uigvo = service.getUI(context.getId(), appId, windowSession, getLocale(),parameters);
} catch(Exception e) {
String errorMessage = e != null ? "(" + e.getMessage() + ")" : "";
String message = key.toString() + " caused exception : <br>" + errorMessage;
cluster.getMessages().add(message);
}
}
if (uigvo != null) {
uigvo.setAppId(context.getId().toString());
uigvo.setDebug(Boolean.valueOf(context.getConfigurationItem(/*
* Configuration.
* DEVELOPMENT_MODE
*/"")));
uigvo.setTitle(context.getName());
stopWatch.stop();
uigvo.setTime(Long.valueOf(stopWatch.getTime()));
logger.info("Application -" + context.getName() + " is rendered in " + stopWatch.getTime() + "ms");
stopWatch.reset();
gvoList.add(uigvo);
} else {
stopWatch.stop();
stopWatch.reset();
String errorMessage = context.getLoadException() != null ? context.getLoadException().getMessage() : "";
String message = "Application [" + key.toString() + "] is not loaded, because of the following:<br>" + errorMessage;
cluster.getMessages().add(message);
}
if (context.getWarningMessages() != null) {
for (String strMsg : context.getWarningMessages()) {
cluster.getMessages().add(strMsg);
}
}
}
}
cluster.setVos(gvoList.toArray(new UIGVO[] {}));
cluster = service.stripCluster(cluster);
return cluster;
} catch (Exception e) {
throw handleException(e);
}
}
}
/**
* Default showcase of components
*/
public UIGVO getUIFromApplicationContext() throws GWTServiceException {
try {
return null;
} catch (Exception e) {
throw handleException(e);
}
}
public UIGVO getUIVO(String xmlUI) throws GWTServiceException {
try {
return service.getUIFromXML(xmlUI, null, null, getLocale());
} catch (Exception e) {
throw handleException(e);
}
}
public String getUI(String xmlUI) throws GWTServiceException {
String url = null;
if (service.isValidXML(xmlUI)) {
logger.fine("XML Send by client : \n" + xmlUI);
try {
String urlBase = ApplicationCluster.getInstance().getConfigurationItem(Configuration.FLEX_DEMO_WAR_URL);
if(urlBase == null || urlBase.length() == 0) {
urlBase = getThreadLocalRequest().getScheme() + "://" + getThreadLocalRequest().getServerName() + ":" + getThreadLocalRequest().getServerPort() + "/qafe-web-flex";
}
String urlStore = urlBase + "/store";
logger.fine("URL Store is =" + urlStore);
OutputStreamWriter wr = null;
BufferedReader rd = null;
try {
// Send data
URL requestURL = new URL(urlStore);
URLConnection conn = requestURL.openConnection();
conn.setDoOutput(true);
wr = new OutputStreamWriter(conn.getOutputStream());
String data = "xml" + "=" + xmlUI;
wr.write(data);
wr.flush();
// Get the response
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
url = urlBase + "/index.jsp?uuid=" + line;
logger.fine(url);
}
} finally {
wr.close();
rd.close();
}
} catch (Exception e) {
throw handleException(e);
}
} else {
try {
service.getUIFromXML(xmlUI, null, null, getLocale());
} catch (Exception e) {
throw handleException(e);
}
}
return url;
}
public String getXMLUIByUUID(String uuid) throws GWTServiceException {
try {
Map<String, String> map = (Map<String, String>) getServletContext().getAttribute("forms-tempmap");
String qamlCode = map.get(uuid);
map.remove(uuid);
return qamlCode;
} catch (Exception e) {
throw handleException(e);
}
}
public GDataObject executeEvent(EventDataGVO eventData) throws GWTServiceException, GWTApplicationStoreException {
StopWatch stopWatch = new StopWatch();
logger.info("Event started[thread id="+ Thread.currentThread().getId() +"]");
stopWatch.start();
try {
String appIdUUID = eventData.getUuid().substring(eventData.getUuid().lastIndexOf('|') + 1);// uuid.substring(uuid.lastIndexOf('|')+1);
ApplicationIdentifier appId = service.getApplicationId(appIdUUID);
GDataObject gDataObject = null;
if (appId != null) {
eventData.setContext(appId.toString());
resolveRequest(eventData);
gDataObject = eventProcessor.execute(eventData, appId, new SessionContainer(getLocale(),eventData.getParameters()));
if (gDataObject != null) {
gDataObject.setTime(Long.valueOf(stopWatch.getTime()));
}
}
//Probably it's not possible to retrieve the user data from the local store.
if (gDataObject == null){
logger.info("gDataObject is null!");
throw new GWTApplicationStoreException();
}
stopWatch.stop();
logger.info("Event ends[thread id="+ Thread.currentThread().getId() +"]");
return gDataObject;
} catch(GWTApplicationStoreException gwtApplicationStoreException){
throw new GWTApplicationStoreException();
} catch (Exception e) {
GWTServiceException gWTServiceException = handleException(e);
gWTServiceException.setGDataObject(ExceptionProcessor.handle(eventData, e));
stopWatch.stop();
if (gWTServiceException.getGDataObject() != null) {
gWTServiceException.getGDataObject().setTime(Long.valueOf(stopWatch.getTime()));
}
logger.info("Event ends[thread id="+ Thread.currentThread().getId() +"]");
throw gWTServiceException;
}
}
protected void resolveRequest(EventDataGVO eventData) {
Map<String, Object> request = new HashMap<String, Object>();
String serverProtocol = getThreadLocalRequest().getProtocol();
if ((serverProtocol != null) && (serverProtocol.split("/").length > 0)) {
serverProtocol = serverProtocol.split("/")[0];
}
String serverContextRoot = getThreadLocalRequest().getRequestURI();
if ((serverContextRoot != null) && (serverContextRoot.split("/").length > 1)) {
serverContextRoot = serverContextRoot.split("/")[1];
}
String serverName = getThreadLocalRequest().getServerName();
String serverPort = String.valueOf(getThreadLocalRequest().getServerPort());
String serverBaseURL = serverProtocol + "://" + serverName + ":" + serverPort + "/" + serverContextRoot;
request.put(EventDataGVO.REQUEST_PROTOCOL, serverProtocol);
request.put(EventDataGVO.REQUEST_SERVER_NAME, serverName);
request.put(EventDataGVO.REQUEST_PORT, serverPort);
request.put(EventDataGVO.REQUEST_CONTEXT_ROOT, serverContextRoot);
request.put(EventDataGVO.REQUEST_BASE_URL, serverBaseURL);
if(eventData.getLocationDataMap() != null) {
request.put(EventDataGVO.REQUEST_GEO, eventData.getLocationDataMap());
}
if (getThreadLocalRequest().getCookies()!=null){
Cookie[] cks = getThreadLocalRequest().getCookies();
Map<String,String> cookies = new HashMap<String,String>();
int length =cks.length;
for (int i =0;i<length;i++){
cookies.put(cks[i].getName(),cks[i].getValue());
}
request.put(EventDataGVO.REQUEST_COOKIES, cookies);
}
/* Improved Request object*/
Map<String,String> requestData = new HashMap<String,String>();
requestData.put(EventDataGVO.REQUEST_PROP_PROTOCOL, serverProtocol);
requestData.put(EventDataGVO.REQUEST_PROP_SERVER_NAME, serverName);
requestData.put(EventDataGVO.REQUEST_PROP_PORT, serverPort);
requestData.put(EventDataGVO.REQUEST_PROP_CONTEXT_ROOT, serverContextRoot);
requestData.put(EventDataGVO.REQUEST_PROP_BASE_URL, serverBaseURL);
request.put(EventDataGVO.REQUEST, requestData);
logger.info(eventData.getMouse().toString());
eventData.setRequest(request);
}
public UIGVO getUIByUUID(String uuid) throws GWTServiceException {
try {
long millis = Calendar.getInstance().getTimeInMillis();
UIGVO ui = null;
// for the openwindow builtin functionality, this uuid needs to be
// "clean"
if (uuid.lastIndexOf('|') > 0) {
String strippedUUID = uuid.substring(uuid.lastIndexOf('|') + 1);
ui = service.getUIByUUID(strippedUUID);
} else {
ui = service.getUIByUUID(uuid);
}
long executionTime = Calendar.getInstance().getTimeInMillis() - millis;
if (ui != null) {
ui.setTime(Long.valueOf(executionTime));
}
return ui;
} catch (Exception e) {
throw handleException(e);
}
}
public void removeUI(String uuid) throws GWTServiceException {
try {
} catch (Exception e) {
throw handleException(e);
}
}
public InitState getMDIState(Map<String,String> parameters) throws GWTServiceException {
try {
String mdiModeParamValue = parameters.get(Configuration.MDI_MODE);
return new InitState(isMDIMode(mdiModeParamValue), ContextLoaderHelper.isDockMode());
} catch (Exception e) {
throw handleException(e);
}
}
private boolean isMDIMode(String mdiModeParamValue) {
String userAgent = getThreadLocalRequest().getHeader("User-Agent");
if (UserAgentUtil.isMobile(userAgent)) {
return false;
}
// Check the dynamic parameter mode.mdi passed with url
if(mdiModeParamValue != null) {
if (mdiModeParamValue.equalsIgnoreCase("true")) {
return true;
} else if(mdiModeParamValue.equalsIgnoreCase("false")){
return false;
}
}
return ContextLoaderHelper.isMDIMode();
}
private Locale getLocale() {
return getThreadLocalRequest().getLocale();
}
public List<DataContainerGVO> getDataForDatagridFromUpload(String uuid) throws GWTServiceException {
List<DataContainerGVO> returnValue = null;
Object o = ApplicationLocalStore.getInstance().retrieve(uuid, uuid);
ApplicationLocalStore.getInstance().delete(uuid, uuid);
if (o instanceof List<?>) {
DataContainerGVO dcg = new SetValueBuiltInRenderer().createContainer(o);
returnValue = dcg.getListofDC();
}
return returnValue;
}
public String prepareForExport(List<DataContainerGVO> list, String exportCode, String header, boolean generateColumnHeader) throws GWTServiceException {
String uuid = DatagridStorageHelper.storeDataGridData(DatagridExportHelper.convert(list), exportCode, header, generateColumnHeader);
return uuid;
}
public void notify(String subject, String message) throws GWTServiceException {
MessageUtil.notifyMessage(subject, message, getThreadLocalRequest());
}
public void removeWindowsEventData(String windowSession, String windowId) {
String lookupKey = windowSession + ApplicationLocalStore.OBJECT_DELIMITER + windowId;
ApplicationLocalStore.getInstance().deleteAll(lookupKey);
}
public void removeFileFromLocalStore(String appUUID, String windowId, String uploadUUID) throws GWTServiceException {
UploadService uploadService = new UploadService();
uploadService.removeUploadedFile(appUUID, windowId, uploadUUID);
}
public String generateTypedCSS(String rendererType, String applicationId) throws GWTServiceException {
String css = CssProvider.getInstance().generateTypedCSS(rendererType, applicationId);
return css;
}
public void removeGloballyStoredData(String windowSession, String applicationId) {
String lookupKey = windowSession + ApplicationLocalStore.OBJECT_DELIMITER + applicationId;
ApplicationLocalStore.getInstance().deleteAll(lookupKey);
}
public GEventItemDataObject executeEventItem(EventItemDataGVO eventItem) throws GWTServiceException, GWTApplicationStoreException {
StopWatch stopWatch = new StopWatch();
logger.info("Event started[thread id="+ Thread.currentThread().getId() +"]");
stopWatch.start();
try {
EventItemProcessor eventItemProcessor = new EventItemProcessorImpl();
Map<String, Object> outputValues = eventItemProcessor.execute(eventItem);
GEventItemDataObject gEventItemDataObject = new GEventItemDataObject();
gEventItemDataObject.setOutputValues(outputValues);
stopWatch.stop();
return gEventItemDataObject;
} catch (Exception e) {
GWTServiceException gWTServiceException = handleException(e);
//gWTServiceException.setGDataObject(ExceptionProcessor.handle(eventData, e));
stopWatch.stop();
if (gWTServiceException.getGDataObject() != null) {
gWTServiceException.getGDataObject().setTime(Long.valueOf(stopWatch.getTime()));
}
logger.info("Event ends[thread id="+ Thread.currentThread().getId() +"]");
throw gWTServiceException;
}
}
/**
* This method is purely used to put data types mentioned in the SerializableWhitelist
* in the GWT whitelist for serialization. The implementation is just a dummy.
*/
public SerializableWhitelist whitelist(SerializableWhitelist value) {
return null;
}
}