001// Copyright 2006-2013 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.corelib.pages;
016
017import org.apache.tapestry5.EventContext;
018import org.apache.tapestry5.SymbolConstants;
019import org.apache.tapestry5.alerts.AlertManager;
020import org.apache.tapestry5.annotations.ContentType;
021import org.apache.tapestry5.annotations.Import;
022import org.apache.tapestry5.annotations.Property;
023import org.apache.tapestry5.annotations.UnknownActivationContextCheck;
024import org.apache.tapestry5.internal.InternalConstants;
025import org.apache.tapestry5.internal.services.PageActivationContextCollector;
026import org.apache.tapestry5.internal.services.ReloadHelper;
027import org.apache.tapestry5.ioc.annotations.Inject;
028import org.apache.tapestry5.ioc.annotations.Symbol;
029import org.apache.tapestry5.ioc.internal.util.InternalUtils;
030import org.apache.tapestry5.services.*;
031
032import java.net.MalformedURLException;
033import java.net.URL;
034import java.util.List;
035import java.util.regex.Pattern;
036
037/**
038 * Responsible for reporting runtime exceptions. This page is quite verbose and is usually overridden in a production
039 * application. When {@link org.apache.tapestry5.SymbolConstants#PRODUCTION_MODE} is "true", it is very abbreviated.
040 *
041 * @see org.apache.tapestry5.corelib.components.ExceptionDisplay
042 */
043@UnknownActivationContextCheck(false)
044@ContentType("text/html")
045@Import(stack = "core", stylesheet = "ExceptionReport.css")
046public class ExceptionReport implements ExceptionReporter
047{
048    private static final String PATH_SEPARATOR_PROPERTY = "path.separator";
049
050    // Match anything ending in .(something?)path.
051
052    private static final Pattern PATH_RECOGNIZER = Pattern.compile("\\..*path$");
053
054    @Property
055    private String attributeName;
056
057    @Inject
058    @Property
059    private Request request;
060
061    @Inject
062    @Symbol(SymbolConstants.PRODUCTION_MODE)
063    @Property(write = false)
064    private boolean productionMode;
065
066    @Inject
067    @Symbol(SymbolConstants.TAPESTRY_VERSION)
068    @Property(write = false)
069    private String tapestryVersion;
070
071    @Inject
072    @Symbol(SymbolConstants.APPLICATION_VERSION)
073    @Property(write = false)
074    private String applicationVersion;
075
076    @Property(write = false)
077    private Throwable rootException;
078
079    @Property
080    private String propertyName;
081
082    @Property
083    private String failurePage;
084
085    @Inject
086    private RequestGlobals requestGlobals;
087
088    @Inject
089    private AlertManager alertManager;
090
091    @Inject
092    private PageActivationContextCollector pageActivationContextCollector;
093
094    @Inject
095    private PageRenderLinkSource linkSource;
096
097    @Inject
098    private BaseURLSource baseURLSource;
099
100    @Inject
101    private ReloadHelper reloadHelper;
102    
103    @Inject
104    private URLEncoder urlEncoder;
105
106    @Property
107    private String rootURL;
108
109    private final String pathSeparator = System.getProperty(PATH_SEPARATOR_PROPERTY);
110
111    public boolean isShowActions() {
112        return failurePage != null && ! request.isXHR();
113    }
114
115    public void reportException(Throwable exception)
116    {
117        rootException = exception;
118
119        failurePage = (request.getAttribute(InternalConstants.ACTIVE_PAGE_LOADED) == null)
120                ? null
121                : requestGlobals.getActivePageName();
122
123        rootURL = baseURLSource.getBaseURL(request.isSecure());
124    }
125
126    public Object[] getReloadContext()
127    {
128        return pageActivationContextCollector.collectPageActivationContext(failurePage);
129    }
130
131    Object onActionFromReloadFirst(EventContext reloadContext)
132    {
133        reloadHelper.forceReload();
134
135        return linkSource.createPageRenderLinkWithContext(urlEncoder.decode(request.getParameter("loadPage")), reloadContext);
136    }
137
138    Object onActionFromReloadRoot() throws MalformedURLException
139    {
140        reloadHelper.forceReload();
141
142        return new URL(baseURLSource.getBaseURL(request.isSecure()));
143    }
144
145
146    public boolean getHasSession()
147    {
148        return request.getSession(false) != null;
149    }
150
151    public Session getSession()
152    {
153        return request.getSession(false);
154    }
155
156    public Object getAttributeValue()
157    {
158        return getSession().getAttribute(attributeName);
159    }
160
161    /**
162     * Returns a <em>sorted</em> list of system property names.
163     */
164    public List<String> getSystemProperties()
165    {
166        return InternalUtils.sortedKeys(System.getProperties());
167    }
168
169    public String getPropertyValue()
170    {
171        return System.getProperty(propertyName);
172    }
173
174    public boolean isComplexProperty()
175    {
176        return PATH_RECOGNIZER.matcher(propertyName).find() && getPropertyValue().contains(pathSeparator);
177    }
178
179    public String[] getComplexPropertyValue()
180    {
181        // Neither : nor ; is a regexp character.
182
183        return getPropertyValue().split(pathSeparator);
184    }
185}