/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.server.headlessclient; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletResponse; import org.apache.wicket.AbstractRestartResponseException; import org.apache.wicket.AccessStackPageMap; import org.apache.wicket.Application; import org.apache.wicket.AttributeModifier; import org.apache.wicket.Component; import org.apache.wicket.IPageMap; import org.apache.wicket.IRequestTarget; import org.apache.wicket.Page; import org.apache.wicket.Request; import org.apache.wicket.RequestCycle; import org.apache.wicket.ResourceReference; import org.apache.wicket.Response; import org.apache.wicket.RestartResponseException; import org.apache.wicket.Session; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.application.IComponentOnBeforeRenderListener; import org.apache.wicket.behavior.AbstractAjaxBehavior; import org.apache.wicket.behavior.IBehavior; import org.apache.wicket.markup.html.PackageResource; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.protocol.http.AjaxEnclosureListener; import org.apache.wicket.protocol.http.BufferedWebResponse; import org.apache.wicket.protocol.http.HttpSessionStore; import org.apache.wicket.protocol.http.MockServletContext; import org.apache.wicket.protocol.http.PageExpiredException; import org.apache.wicket.protocol.http.RequestUtils; import org.apache.wicket.protocol.http.WebApplication; import org.apache.wicket.protocol.http.WebRequest; import org.apache.wicket.protocol.http.WebResponse; import org.apache.wicket.protocol.http.WicketFilter; import org.apache.wicket.protocol.http.request.CryptedUrlWebRequestCodingStrategy; import org.apache.wicket.protocol.http.request.urlcompressing.UrlCompressingWebCodingStrategy; import org.apache.wicket.protocol.http.request.urlcompressing.UrlCompressingWebRequestProcessor; import org.apache.wicket.request.IRequestCodingStrategy; import org.apache.wicket.request.IRequestCycleProcessor; import org.apache.wicket.request.RequestParameters; import org.apache.wicket.request.target.basic.EmptyAjaxRequestTarget; import org.apache.wicket.request.target.basic.EmptyRequestTarget; import org.apache.wicket.request.target.coding.BookmarkablePageRequestTargetUrlCodingStrategy; import org.apache.wicket.request.target.coding.HybridUrlCodingStrategy; import org.apache.wicket.request.target.coding.SharedResourceRequestTargetUrlCodingStrategy; import org.apache.wicket.request.target.component.listener.BehaviorRequestTarget; import org.apache.wicket.request.target.resource.SharedResourceRequestTarget; import org.apache.wicket.session.ISessionStore; import org.apache.wicket.session.pagemap.IPageMapEntry; import org.apache.wicket.settings.IRequestCycleSettings; import org.apache.wicket.util.lang.Bytes; import org.apache.wicket.util.string.AppendingStringBuffer; import org.apache.wicket.util.string.Strings; import org.apache.wicket.util.time.Duration; import org.apache.wicket.util.value.ValueMap; import org.odlabs.wiquery.core.commons.IWiQuerySettings; import org.odlabs.wiquery.core.commons.WiQuerySettings; import org.odlabs.wiquery.ui.themes.IThemableApplication; import com.servoy.j2db.FormManager; import com.servoy.j2db.IApplication; import com.servoy.j2db.component.ServoyBeanState; import com.servoy.j2db.dataprocessing.IRecord; import com.servoy.j2db.dataui.IServoyAwareBean; import com.servoy.j2db.scripting.FormScope; import com.servoy.j2db.server.headlessclient.dataui.RecordItemModel; import com.servoy.j2db.server.headlessclient.dataui.WebBaseLabel; import com.servoy.j2db.server.headlessclient.dataui.WebBaseSelectBox; import com.servoy.j2db.server.headlessclient.dataui.WebCellBasedView; import com.servoy.j2db.server.headlessclient.dataui.WebDataCheckBoxChoice; import com.servoy.j2db.server.headlessclient.dataui.WebDataComboBox; import com.servoy.j2db.server.headlessclient.dataui.WebDataHtmlArea; import com.servoy.j2db.server.headlessclient.dataui.WebDataListBox; import com.servoy.j2db.server.headlessclient.dataui.WebDataLookupField; import com.servoy.j2db.server.headlessclient.dataui.WebDataRadioChoice; import com.servoy.j2db.server.headlessclient.jquery.JQueryLoader; import com.servoy.j2db.server.headlessclient.mask.MaskBehavior; import com.servoy.j2db.server.headlessclient.tinymce.TinyMCELoader; import com.servoy.j2db.server.headlessclient.yui.YUILoader; import com.servoy.j2db.server.shared.ApplicationServerRegistry; import com.servoy.j2db.server.shared.IWebClientSessionFactory; import com.servoy.j2db.ui.IFieldComponent; import com.servoy.j2db.ui.ISupportEventExecutor; import com.servoy.j2db.ui.ISupportOnRenderCallback; import com.servoy.j2db.util.Debug; import com.servoy.j2db.util.Settings; import com.servoy.j2db.util.Utils; /** * Class to create (special)sessions and is a container which can hold a reference to ApplicationServer (actually application server should have bin the * org.apache.wicket application but it requires to be a subclass from webapp) * * @author jblok */ public class WebClientsApplication extends WebApplication implements IWiQuerySettings, IThemableApplication { /** * @author jcompagner * */ private final class ServoyCryptedUrlWebRequestCodingStrategy extends CryptedUrlWebRequestCodingStrategy { private final IRequestCodingStrategy defaultStrategy; /** * @param defaultStrategy */ private ServoyCryptedUrlWebRequestCodingStrategy(IRequestCodingStrategy defaultStrategy) { super(defaultStrategy); this.defaultStrategy = defaultStrategy; } @SuppressWarnings("nls") @Override protected String decodeURL(String url) { try { return super.decodeURL(url); } catch (Exception ex) { Debug.trace("Unable to decode the url: '" + url + "' most likely because the session expired", ex); // just ignore this more gracefully and redirect once to main page. WebClientSession webClientSession = (WebClientSession)Session.get(); WebClient webClient = webClientSession.getWebClient(); if (webClient != null) { if (webClient.isInDeveloper()) { throw new RestartResponseException(getApplicationSettings().getPageExpiredErrorPage()); } else { throw new RestartResponseException(webClient.getMainPage()); } } else { if (((WebRequest)RequestCycle.get().getRequest()).isAjax()) { RequestCycle.get().setRequestTarget(new RedirectAjaxRequestTarget(getApplicationSettings().getPageExpiredErrorPage())); throw new AbstractRestartResponseException() { }; } else { throw new RestartResponseException(getApplicationSettings().getPageExpiredErrorPage()); } } } } @Override protected CharSequence encodeURL(CharSequence url) { if (Session.get() != null && !Session.get().isSessionInvalidated()) return super.encodeURL(url); return url; } /** * @see org.apache.wicket.protocol.http.request.CryptedUrlWebRequestCodingStrategy#encode(org.apache.wicket.RequestCycle, * org.apache.wicket.IRequestTarget) */ @Override public CharSequence encode(RequestCycle requestCycle, IRequestTarget requestTarget) { if (requestTarget instanceof SharedResourceRequestTarget) { return defaultStrategy.encode(requestCycle, requestTarget); } return super.encode(requestCycle, requestTarget); } } private SharedMediaResource sharedMediaResource; private RequestCycleSettings rcSettings; /** * Constructor */ public WebClientsApplication() { super(); } /* * (non-Javadoc) * * @see org.apache.wicket.Application#onDestroy() */ @Override protected void onDestroy() { SessionClient.onDestroy(); } public WebClientsApplication fakeInit() { setWicketFilter(new WicketFilter() { private static final long serialVersionUID = 1L; /** * @see wicket.protocol.http.WicketFilter#getFilterConfig() */ @Override public FilterConfig getFilterConfig() { return new FilterConfig() { public String getFilterName() { return "fakeservlet"; //$NON-NLS-1$ } public String getInitParameter(String arg0) { return Application.DEPLOYMENT; } public Enumeration<String> getInitParameterNames() { return new Enumeration<String>() { int i = 0; /** * @see java.util.Enumeration#hasMoreElements() */ public boolean hasMoreElements() { return i == 0; } /** * @see java.util.Enumeration#nextElement() */ public String nextElement() { i++; return Application.CONFIGURATION; } }; } public ServletContext getServletContext() { return new MockServletContext(WebClientsApplication.this, null); } }; } }); internalInit(); return this; } @Override public RequestCycleSettings getRequestCycleSettings() { if (rcSettings == null) { IRequestCycleSettings superSettings = super.getRequestCycleSettings(); if (superSettings != null) rcSettings = new RequestCycleSettings(superSettings); } return rcSettings; } /** * @see wicket.protocol.http.WebApplication#init() */ @Override protected void init() { if (ApplicationServerRegistry.get() == null) return; // TODO this is a workaround to allow mobile test client that only starts Tomcat not to give exceptions (please remove if mobile test client initialises a full app. server in the future) getResourceSettings().setResourceWatcher(new ServoyModificationWatcher(Duration.seconds(5))); // getResourceSettings().setResourcePollFrequency(Duration.seconds(5)); getResourceSettings().setAddLastModifiedTimeToResourceReferenceUrl(true); getResourceSettings().setDefaultCacheDuration((int)Duration.days(365).seconds()); getMarkupSettings().setCompressWhitespace(true); getMarkupSettings().setMarkupCache(new ServoyMarkupCache(this)); // getMarkupSettings().setStripWicketTags(true); getResourceSettings().setResourceStreamLocator(new ServoyResourceStreamLocator(this)); getResourceSettings().setPackageResourceGuard(new ServoyPackageResourceGuard()); // getResourceSettings().setResourceFinder(createResourceFinder()); getResourceSettings().setThrowExceptionOnMissingResource(false); getApplicationSettings().setPageExpiredErrorPage(ServoyExpiredPage.class); getApplicationSettings().setClassResolver(new ServoyClassResolver()); getSessionSettings().setMaxPageMaps(15); // getRequestCycleSettings().setGatherExtendedBrowserInfo(true); getSecuritySettings().setCryptFactory(new CachingKeyInSessionSunJceCryptFactory()); Settings settings = Settings.getInstance(); getDebugSettings().setOutputComponentPath(Utils.getAsBoolean(settings.getProperty("servoy.webclient.debug.wicketpath", "false"))); //$NON-NLS-1$ //$NON-NLS-2$ if (Utils.getAsBoolean(settings.getProperty("servoy.webclient.nice.urls", "false"))) //$NON-NLS-1$ //$NON-NLS-2$ { mount(new HybridUrlCodingStrategy("/solutions", SolutionLoader.class)); //$NON-NLS-1$ mount(new HybridUrlCodingStrategy("/application", MainPage.class)); //$NON-NLS-1$ mount(new HybridUrlCodingStrategy("/ss", SolutionLoader.class) //$NON-NLS-1$ { /** * @see wicket.request.target.coding.BookmarkablePageRequestTargetUrlCodingStrategy#matches(wicket.IRequestTarget) */ @Override public boolean matches(IRequestTarget requestTarget) { return false; } }); } else { mountBookmarkablePage("/solutions", SolutionLoader.class); //$NON-NLS-1$ mount(new BookmarkablePageRequestTargetUrlCodingStrategy("/ss", SolutionLoader.class, null) //$NON-NLS-1$ { /** * @see wicket.request.target.coding.BookmarkablePageRequestTargetUrlCodingStrategy#matches(wicket.IRequestTarget) */ @Override public boolean matches(IRequestTarget requestTarget) { return false; } }); } long maxSize = Utils.getAsLong(settings.getProperty("servoy.webclient.maxuploadsize", "0"), false); //$NON-NLS-1$ //$NON-NLS-2$ if (maxSize > 0) { getApplicationSettings().setDefaultMaximumUploadSize(Bytes.kilobytes(maxSize)); } getSharedResources().putClassAlias(IApplication.class, "application"); //$NON-NLS-1$ getSharedResources().putClassAlias(PageContributor.class, "pc"); //$NON-NLS-1$ getSharedResources().putClassAlias(MaskBehavior.class, "mask"); //$NON-NLS-1$ getSharedResources().putClassAlias(Application.class, "servoy"); //$NON-NLS-1$ getSharedResources().putClassAlias(org.wicketstuff.calendar.markup.html.form.DatePicker.class, "datepicker"); //$NON-NLS-1$ getSharedResources().putClassAlias(YUILoader.class, "yui"); //$NON-NLS-1$ getSharedResources().putClassAlias(JQueryLoader.class, "jquery"); //$NON-NLS-1$ getSharedResources().putClassAlias(TinyMCELoader.class, "tinymce"); //$NON-NLS-1$ getSharedResources().putClassAlias(org.apache.wicket.markup.html.WicketEventReference.class, "wicketevent"); //$NON-NLS-1$ getSharedResources().putClassAlias(org.apache.wicket.ajax.WicketAjaxReference.class, "wicketajax"); //$NON-NLS-1$ getSharedResources().putClassAlias(MainPage.class, "servoyjs"); //$NON-NLS-1$ getSharedResources().putClassAlias(org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow.class, "modalwindow"); //$NON-NLS-1$ PackageResource.bind(this, IApplication.class, "images/open_project.gif"); //$NON-NLS-1$ PackageResource.bind(this, IApplication.class, "images/save.gif"); //$NON-NLS-1$ mountSharedResource("/formcss", "servoy/formcss"); //$NON-NLS-1$//$NON-NLS-2$ sharedMediaResource = new SharedMediaResource(); getSharedResources().add("media", sharedMediaResource); //$NON-NLS-1$ mount(new SharedResourceRequestTargetUrlCodingStrategy("mediafolder", "servoy/media") //$NON-NLS-1$ //$NON-NLS-2$ { @Override protected void appendParameters(AppendingStringBuffer url, Map<String, ? > parameters) { if (parameters != null && parameters.size() > 0) { Object solutionName = parameters.get("s"); //$NON-NLS-1$ if (solutionName != null) appendPathParameter(url, null, solutionName.toString()); Object resourceId = parameters.get("id"); //$NON-NLS-1$ if (resourceId != null) appendPathParameter(url, null, resourceId.toString()); StringBuilder queryParams = new StringBuilder(); for (Entry< ? , ? > entry1 : parameters.entrySet()) { Object value = ((Entry< ? , ? >)entry1).getValue(); if (value != null) { Object key = ((Entry< ? , ? >)entry1).getKey(); if (!"s".equals(key) && !"id".equals(key)) //$NON-NLS-1$ //$NON-NLS-2$ { if (value instanceof String[]) { String[] values = (String[])value; for (String value1 : values) { if (queryParams.length() > 0) queryParams.append("&"); //$NON-NLS-1$ queryParams.append(key).append("=").append(value1);//$NON-NLS-1$ } } else { if (queryParams.length() > 0) queryParams.append("&"); //$NON-NLS-1$ queryParams.append(key).append("=").append(value);//$NON-NLS-1$ } } } } if (queryParams.length() > 0) { url.append("?").append(queryParams);//$NON-NLS-1$ } } } @Override protected void appendPathParameter(AppendingStringBuffer url, String key, String value) { String escapedValue = value; String[] values = escapedValue.split("/");//$NON-NLS-1$ if (values.length > 1) { StringBuilder sb = new StringBuilder(escapedValue.length()); for (String str : values) { sb.append(urlEncodePathComponent(str)); sb.append('/'); } sb.setLength(sb.length() - 1); escapedValue = sb.toString(); } else { escapedValue = urlEncodePathComponent(escapedValue); } if (!Strings.isEmpty(escapedValue)) { if (!url.endsWith("/"))//$NON-NLS-1$ { url.append("/");//$NON-NLS-1$ } if (key != null) url.append(urlEncodePathComponent(key)).append("/");//$NON-NLS-1$ url.append(escapedValue); } } /* * (non-Javadoc) * * @see org.apache.wicket.request.target.coding.AbstractRequestTargetUrlCodingStrategy#decodeParameters(java.lang.String, java.util.Map) */ @Override protected ValueMap decodeParameters(String urlFragment, Map<String, ? > urlParameters) { ValueMap map = new ValueMap(); final String[] pairs = urlFragment.split("/"); //$NON-NLS-1$ if (pairs.length > 1) { map.add("s", pairs[1]); //$NON-NLS-1$ StringBuffer sb = new StringBuffer(); for (int i = 2; i < pairs.length; i++) { sb.append(pairs[i]); sb.append("/"); //$NON-NLS-1$ } sb.setLength(sb.length() - 1); map.add("id", sb.toString()); //$NON-NLS-1$ } if (urlParameters != null) { map.putAll(urlParameters); } return map; } }); getSharedResources().add("resources", new ServeResources()); //$NON-NLS-1$ getSharedResources().add("formcss", new FormCssResource(this)); //$NON-NLS-1$ if (settings.getProperty("servoy.webclient.error.page", null) != null) //$NON-NLS-1$ { getApplicationSettings().setInternalErrorPage(ServoyErrorPage.class); } if (settings.getProperty("servoy.webclient.pageexpired.page", null) != null) //$NON-NLS-1$ { getApplicationSettings().setPageExpiredErrorPage(ServoyPageExpiredPage.class); } addPreComponentOnBeforeRenderListener(new IComponentOnBeforeRenderListener() { public void onBeforeRender(Component component) { if (component instanceof IServoyAwareBean) { IModel model = component.getInnermostModel(); WebForm webForm = component.findParent(WebForm.class); if (model instanceof RecordItemModel && webForm != null) { IRecord record = (IRecord)((RecordItemModel)model).getObject(); FormScope fs = webForm.getController().getFormScope(); if (record != null && fs != null) { ((IServoyAwareBean)component).setSelectedRecord(new ServoyBeanState(record, fs)); } } } else { if (!component.isEnabled()) { boolean hasOnRender = (component instanceof IFieldComponent && ((IFieldComponent)component).getScriptObject() instanceof ISupportOnRenderCallback && ((ISupportOnRenderCallback)((IFieldComponent)component).getScriptObject()).getRenderEventExecutor().hasRenderCallback()); if (!hasOnRender) { // onrender may change the enable state return; } } Component targetComponent = null; boolean hasFocus = false, hasBlur = false; if (component instanceof IFieldComponent && ((IFieldComponent)component).getEventExecutor() != null) { targetComponent = component; if (component instanceof WebBaseSelectBox) { Component[] cs = ((WebBaseSelectBox)component).getFocusChildren(); if (cs != null && cs.length == 1) targetComponent = cs[0]; } if (component instanceof WebDataHtmlArea) hasFocus = true; // always install a focus handler when in a table view to detect change of selectedIndex and test for record validation if (((IFieldComponent)component).getEventExecutor().hasEnterCmds() || component.findParent(WebCellBasedView.class) != null || (((IFieldComponent)component).getScriptObject() instanceof ISupportOnRenderCallback && ((ISupportOnRenderCallback)((IFieldComponent)component).getScriptObject()).getRenderEventExecutor().hasRenderCallback())) { hasFocus = true; } // Always trigger event on focus lost: // 1) check for new selected index, record validation may have failed preventing a index changed // 2) prevent focus gained to be called when field validation failed // 3) general ondata change hasBlur = true; } else if (component instanceof WebBaseLabel) { targetComponent = component; hasFocus = true; } if (targetComponent != null) { MainPage mainPage = targetComponent.findParent(MainPage.class); if (mainPage.isUsingAjax()) { AbstractAjaxBehavior eventCallback = mainPage.getPageContributor().getEventCallback(); if (eventCallback != null) { String callback = eventCallback.getCallbackUrl().toString(); if (component instanceof WebDataRadioChoice || component instanceof WebDataCheckBoxChoice || component instanceof WebDataLookupField || component instanceof WebDataComboBox || component instanceof WebDataListBox || component instanceof WebDataHtmlArea) { // is updated via ServoyChoiceComponentUpdatingBehavior or ServoyFormComponentUpdatingBehavior, this is just for events callback += "&nopostdata=true"; } for (IBehavior behavior : targetComponent.getBehaviors()) { if (behavior instanceof EventCallbackModifier) { targetComponent.remove(behavior); } } if (hasFocus) { StringBuilder js = new StringBuilder(); js.append("eventCallback(this,'focus','").append(callback).append("',event)"); //$NON-NLS-1$ //$NON-NLS-2$ targetComponent.add(new EventCallbackModifier("onfocus", true, new Model<String>(js.toString()))); //$NON-NLS-1$ targetComponent.add(new EventCallbackModifier("onmousedown", true, new Model<String>("focusMousedownCallback(event)"))); //$NON-NLS-1$ //$NON-NLS-2$ } if (hasBlur) { boolean blockRequest = false; // if component has ondatachange, check for blockrequest if (component instanceof ISupportEventExecutor && ((ISupportEventExecutor)component).getEventExecutor().hasChangeCmd()) { WebClientSession webClientSession = WebClientSession.get(); blockRequest = webClientSession != null && webClientSession.blockRequest(); } StringBuilder js = new StringBuilder(); js.append("postEventCallback(this,'blur','").append(callback).append("',event," + blockRequest + ")"); //$NON-NLS-1$ //$NON-NLS-2$ targetComponent.add(new EventCallbackModifier("onblur", true, new Model<String>(js.toString()))); //$NON-NLS-1$ } } } } } } }); } public SharedMediaResource getSharedMediaResource() { return sharedMediaResource; } /* * (non-Javadoc) * * @see org.apache.wicket.protocol.http.WebApplication#newWebResponse(javax.servlet.http.HttpServletResponse) */ @Override protected WebResponse newWebResponse(HttpServletResponse servletResponse) { // over ride this so that redirects are not relative but absolute // Websphere doesn't work correctly with relative urls. return (getRequestCycleSettings().getBufferResponse() ? new BufferedWebResponse(servletResponse) { private String reqUrl = null; @Override public CharSequence encodeURL(CharSequence url) { if (reqUrl == null) reqUrl = ((WebRequest)RequestCycle.get().getRequest()).getHttpServletRequest().getRequestURI(); return super.encodeURL(url); } @Override protected void sendRedirect(String url) throws IOException { if (reqUrl != null && url.indexOf("://") == -1) //$NON-NLS-1$ { String absUrl = RequestUtils.toAbsolutePath(reqUrl, url); getHttpServletResponse().sendRedirect(absUrl); } else { super.sendRedirect(url); } } } : new WebResponse(servletResponse) { @Override protected void sendRedirect(String url) throws IOException { String reqUrl = ((WebRequest)RequestCycle.get().getRequest()).getHttpServletRequest().getRequestURI(); String absUrl = RequestUtils.toAbsolutePath(reqUrl, url); getHttpServletResponse().sendRedirect(absUrl); } }); } /** * @see wicket.Application#getHomePage() */ @Override public Class<SelectSolution> getHomePage() { return SelectSolution.class; } @SuppressWarnings("nls") @Override public synchronized Session newSession(Request request, Response response) { ISessionStore sessionStore = getSessionStore(); Session session = sessionStore.lookup(request); if (session == null) { IWebClientSessionFactory webClientSessionFactory = ApplicationServerRegistry.get().getWebClientSessionFactory(); if (webClientSessionFactory == null) { throw new IllegalStateException("Server was not started for web client usage"); } session = webClientSessionFactory.newSession(request, response); session.bind(); } return session; } @Override protected IRequestCycleProcessor newRequestCycleProcessor() { return new UrlCompressingWebRequestProcessor() { @Override public void respond(RequestCycle requestCycle) { // execute events from WebClient.invokeLater() before the respond (render) is started Session session = Session.get(); if (session instanceof WebClientSession && ((WebClientSession)session).getWebClient() != null) { ((WebClientSession)session).getWebClient().executeEvents(); } super.respond(requestCycle); } /** * @see wicket.protocol.http.WebRequestCycleProcessor#newRequestCodingStrategy() */ @Override protected IRequestCodingStrategy newRequestCodingStrategy() { Settings settings = Settings.getInstance(); if (Utils.getAsBoolean(settings.getProperty("servoy.webclient.crypt-urls", "true"))) //$NON-NLS-1$ //$NON-NLS-2$ { return new ServoyCryptedUrlWebRequestCodingStrategy(new UrlCompressingWebCodingStrategy()); } else { return new UrlCompressingWebCodingStrategy(); } } @Override protected IRequestTarget resolveListenerInterfaceTarget(RequestCycle requestCycle, Page page, String componentPath, String interfaceName, RequestParameters requestParameters) { try { IRequestTarget requestTarget = super.resolveListenerInterfaceTarget(requestCycle, page, componentPath, interfaceName, requestParameters); if (requestTarget instanceof BehaviorRequestTarget) { Component target = ((BehaviorRequestTarget)requestTarget).getTarget(); if (!(target instanceof Page)) { boolean invalidPage = false; Page page2 = null; try { page2 = target.findParent(Page.class); // test if it has a page. } catch (Exception e) { Debug.trace(e); invalidPage = true; } if (page2 == null || !page2.getId().equals(page.getId())) { invalidPage = true; } if (invalidPage) { Debug.log("Couldn't resolve the page of the component, component already gone from page? returning empty"); //$NON-NLS-1$ return EmptyRequestTarget.getInstance(); } } } return requestTarget; } catch (Exception e) { Debug.log("couldnt resolve interface, component page already gone from page? returning empty"); //$NON-NLS-1$ } return EmptyRequestTarget.getInstance(); } @Override public IRequestTarget resolve(final RequestCycle requestCycle, final RequestParameters requestParameters) { try { return super.resolve(requestCycle, requestParameters); } catch (PageExpiredException e) { // if there is a page expired exception // then ignore it if there is a current form. Debug.trace("Page expired, checking for a current form"); //$NON-NLS-1$ Request request = requestCycle.getRequest(); if (request instanceof WebRequest && ((WebRequest)request).isAjax() && requestParameters.isOnlyProcessIfPathActive()) { Debug.trace("Page expired, it is an ajan/process only if active request"); //$NON-NLS-1$ Session session = Session.get(); if (session instanceof WebClientSession && ((WebClientSession)session).getWebClient() != null) { WebClient webClient = ((WebClientSession)session).getWebClient(); if (webClient.getFormManager().getCurrentForm() != null) { Debug.trace("Page expired, there is a current form, ignore this ajax request"); //$NON-NLS-1$ return EmptyAjaxRequestTarget.getInstance(); } } } throw e; } } }; } /** * @see wicket.protocol.http.WebApplication#newSessionStore() */ @Override protected ISessionStore newSessionStore() { return new HttpSessionStore(this) { @Override public IPageMap createPageMap(String name) { return new ModifiedAccessStackPageMap(name); } }; } /* * (non-Javadoc) * * @see org.apache.wicket.protocol.http.WebApplication#newAjaxRequestTarget(org.apache.wicket.Page) */ @Override public AjaxRequestTarget newAjaxRequestTarget(Page page) { AjaxRequestTarget target = new CloseableAjaxRequestTarget(page); target.addListener(new AjaxEnclosureListener()); return target; } /** * @see org.apache.wicket.protocol.http.WebApplication#newRequestCycle(org.apache.wicket.Request, org.apache.wicket.Response) */ @Override public RequestCycle newRequestCycle(Request request, Response response) { // Respond to request return new ServoyRequestCycle(this, (WebRequest)request, (WebResponse)response); } public WiQuerySettings getWiQuerySettings() { WiQuerySettings settings = new WiQuerySettings(); if (getDebugSettings().isAjaxDebugModeEnabled()) { settings.setJQueryCoreResourceReference(JQueryLoader.JS_JQUERY_DEBUG); } else { settings.setJQueryCoreResourceReference(JQueryLoader.JS_JQUERY); } return settings; } public ResourceReference getTheme(Session session) { return JQueryLoader.CSS_UI; } public class ModifiedAccessStackPageMap extends AccessStackPageMap { public ModifiedAccessStackPageMap(final String name) { super(name); } public void flagDirty() { super.dirty(); } @Override public void removeEntry(IPageMapEntry entry) { if (entry instanceof MainPage) { WebClient webClient = WebClientSession.get().getWebClient(); ((FormManager)webClient.getFormManager()).removeContainer(getName()); } super.removeEntry(entry); } } private class EventCallbackModifier extends AttributeModifier { private static final String STR_EVENT_CALLBACK = "eventCallback("; //$NON-NLS-1$ private static final String STR_POST_EVENT_CALLBACK = "postEventCallback("; //$NON-NLS-1$ private static final String STR_FOCUS_MOUSEDOWN_CALLBACK = "focusMousedownCallback("; //$NON-NLS-1$ EventCallbackModifier(final String attribute, final boolean addAttributeIfNotPresent, final IModel< ? > replaceModel) { super(attribute, addAttributeIfNotPresent, replaceModel); } @Override protected String newValue(final String currentValue, final String replacementValue) { if (currentValue != null) { if (replacementValue != null) { StringBuilder newValue = new StringBuilder(); Iterator<String> st = getTokens(currentValue).iterator(); String t; boolean replacementValueAdded = false; while (st.hasNext()) { t = st.next(); if ((t.startsWith(STR_EVENT_CALLBACK) && replacementValue.startsWith(STR_EVENT_CALLBACK)) || (t.startsWith(STR_POST_EVENT_CALLBACK) && replacementValue.startsWith(STR_POST_EVENT_CALLBACK)) || (t.startsWith(STR_FOCUS_MOUSEDOWN_CALLBACK) && replacementValue.startsWith(STR_FOCUS_MOUSEDOWN_CALLBACK))) { newValue.append(replacementValue); replacementValueAdded = true; } else { newValue.append(t); } newValue.append(';'); } if (!replacementValueAdded) newValue.append(replacementValue); if (newValue.length() > 0) return newValue.toString(); } return currentValue; } return replacementValue; } private ArrayList<String> getTokens(String s) { ArrayList<String> tokens = new ArrayList<String>(); int start = 0; int index = 0; int len = s.length(); boolean parsingQuote = false; char quote = 0; while (index < len) { switch (s.charAt(index)) { case ';' : if (!parsingQuote) { tokens.add(s.substring(start, index)); start = index + 1; } break; case '"' : case '\'' : if (index > 0 && s.charAt(index - 1) == '\\') break; if (parsingQuote) { if (quote == s.charAt(index)) { parsingQuote = false; } } else { parsingQuote = true; quote = s.charAt(index); } } index++; } if (tokens.size() == 0) tokens.add(s); return tokens; } } }