/**
* Copyright (C) 2009 eXo Platform SAS.
*
* This 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 software 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.portal.webui.workspace;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.exoplatform.portal.application.StandaloneAppRequestContext;
import org.exoplatform.portal.resource.Skin;
import org.exoplatform.portal.resource.SkinService;
import org.exoplatform.portal.url.URLWriter;
import org.exoplatform.portal.webui.application.UIStandaloneAppContainer;
import org.exoplatform.services.resources.Orientation;
import org.exoplatform.web.application.JavascriptManager;
import org.exoplatform.web.application.javascript.JavascriptConfigService;
import org.exoplatform.web.url.MimeType;
import org.exoplatform.webui.application.WebuiRequestContext;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.core.UIApplication;
import org.exoplatform.webui.core.UIComponent;
import org.exoplatform.webui.url.ComponentURL;
import org.gatein.portal.controller.resource.ResourceId;
import org.gatein.portal.controller.resource.ResourceScope;
import org.gatein.portal.controller.resource.script.FetchMap;
import org.gatein.portal.controller.resource.script.FetchMode;
import org.gatein.portal.controller.resource.script.Module;
import org.gatein.portal.controller.resource.script.ScriptResource;
import org.json.JSONObject;
@ComponentConfig(lifecycle = UIStandaloneApplicationLifecycle.class, template = "system:/groovy/portal/webui/workspace/UIStandaloneApplication.gtmpl")
public class UIStandaloneApplication extends UIApplication {
public static final int NORMAL_MODE = 0;
// modeState, locale, skin_, orientation will be used when we display portlet in standalone mode
private int modeState = NORMAL_MODE;
private Locale locale_ = Locale.ENGLISH;
private String skin_ = "Default";
private Orientation orientation_ = Orientation.LT;
private boolean isSessionOpen = false;
public static final UIComponent EMPTY_COMPONENT = new UIComponent() {
public String getId() {
return "{portal:componentId}";
};
};
public UIStandaloneApplication() throws Exception {
addChild(UIStandaloneAppContainer.class, null, null);
}
// Temporary need this, don't want to render UIPopupMessage
public void renderChildren() throws Exception {
WebuiRequestContext context = WebuiRequestContext.getCurrentInstance();
super.renderChildren(context);
}
@Override
public void processDecode(WebuiRequestContext context) throws Exception {
String storageId = ((StandaloneAppRequestContext) context).getStorageId();
UIStandaloneAppContainer staContaner = getChild(UIStandaloneAppContainer.class);
if (!storageId.equals(staContaner.getCurrStorageId())) {
staContaner.setCurrStorageId(storageId);
}
super.processDecode(context);
}
public void processRender(WebuiRequestContext context) throws Exception {
Writer w = context.getWriter();
//
if (!context.useAjax()) {
super.processRender(context);
} else {
Set<UIComponent> list = context.getUIComponentToUpdateByAjax();
w.write("<div class=\"PortalResponse\">");
w.write("<div class=\"PortalResponseData\">");
if (list != null) {
for (UIComponent uicomponent : list) {
if (log.isDebugEnabled()) {
log.debug("AJAX call: Need to refresh the UI component " + uicomponent.getName());
}
renderBlockToUpdate(uicomponent, context, w);
}
}
w.write("</div>");
w.write("<div class=\"LoadingScripts\">");
writeLoadingScripts(context);
w.write("</div>");
w.write("<div class=\"PortalResponseScript\">");
JavascriptManager jsManager = context.getJavascriptManager();
w.write(jsManager.getJavaScripts());
w.write("</div>");
w.write("</div>");
}
}
private void writeLoadingScripts(WebuiRequestContext context) throws Exception {
Writer w = context.getWriter();
Map<String, Boolean> scriptURLs = getScripts();
w.write("<div class=\"ImmediateScripts\">");
w.write(StringUtils.join(scriptURLs.keySet(), ","));
w.write("</div>");
}
public Map<String, Boolean> getScripts() {
WebuiRequestContext context = WebuiRequestContext.getCurrentInstance();
JavascriptManager jsMan = context.getJavascriptManager();
// Need to add bootstrap as immediate since it contains the loader
jsMan.loadScriptResource(ResourceScope.SHARED, "bootstrap");
//
FetchMap<ResourceId> requiredResources = jsMan.getScriptResources();
log.debug("Resource ids to resolve: {}", requiredResources);
//
JavascriptConfigService service = getApplicationComponent(JavascriptConfigService.class);
LinkedHashMap<String, Boolean> ret = new LinkedHashMap<String, Boolean>();
Map<ScriptResource, FetchMode> tmp = service.resolveIds(requiredResources);
for (ScriptResource rs : tmp.keySet()) {
ResourceId id = rs.getId();
boolean isRemote = !rs.isEmpty() && rs.getModules().get(0) instanceof Module.Remote;
ret.put(id.toString(), isRemote);
}
for (String url : jsMan.getExtendedScriptURLs()) {
ret.put(url, true);
}
//
log.debug("Resolved resources for page: " + ret);
return ret;
}
public JSONObject getJSConfig() throws Exception {
JavascriptConfigService service = getApplicationComponent(JavascriptConfigService.class);
StandaloneAppRequestContext context = WebuiRequestContext.getCurrentInstance();
return service.getJSConfig(context.getControllerContext(), context.getLocale());
}
public Collection<Skin> getPortalSkins() {
SkinService skinService = getApplicationComponent(SkinService.class);
Collection<Skin> skins = new ArrayList<Skin>(skinService.getPortalSkins(skin_));
return skins;
}
public Set<Skin> getPortletSkins() {
Set<Skin> skins = new HashSet<Skin>();
return skins;
}
public boolean isSessionOpen() {
return isSessionOpen;
}
public void setSessionOpen(boolean isSessionOpen) {
this.isSessionOpen = isSessionOpen;
}
public String getSkin() {
return skin_;
}
public Orientation getOrientation() {
return orientation_;
}
public void setOrientation(Orientation orientation) {
this.orientation_ = orientation;
}
public Locale getLocale() {
return locale_;
}
public void setLocale(Locale locale) {
locale_ = locale;
}
public void setModeState(int mode) {
this.modeState = mode;
}
public int getModeState() {
return modeState;
}
/**
* Return the portal url template which will be sent to client ( browser ) and used for JS based portal url generation.
*
* <p>
* The portal url template are calculated base on the current request and site state. Something like :
* <code>"/portal/g/:platform:administrators/administration/registry?portal:componentId={portal:uicomponentId}&portal:action={portal:action}" ;</code>
*
* @return return portal url template
* @throws java.io.UnsupportedEncodingException
*/
public String getPortalURLTemplate() throws UnsupportedEncodingException {
StandaloneAppRequestContext context = WebuiRequestContext.getCurrentInstance();
ComponentURL urlTemplate = context.createURL(ComponentURL.TYPE);
if (URLWriter.isUrlEncoded()) {
urlTemplate.setMimeType(MimeType.XHTML);
} else {
urlTemplate.setMimeType(MimeType.PLAIN);
}
urlTemplate.setPath(context.getNodePath());
urlTemplate.setResource(EMPTY_COMPONENT);
urlTemplate.setAction("{portal:action}");
return URLDecoder.decode(urlTemplate.toString(), "UTF-8");
}
}