You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2007/02/15 03:27:13 UTC
svn commit: r507781 - in /tapestry/tapestry5/tapestry-core/trunk/src:
main/java/org/apache/tapestry/
main/java/org/apache/tapestry/internal/services/
main/java/org/apache/tapestry/services/
main/resources/org/apache/tapestry/internal/services/ site/apt...
Author: hlship
Date: Wed Feb 14 18:27:11 2007
New Revision: 507781
URL: http://svn.apache.org/viewvc?view=rev&rev=507781
Log:
Improve error messages when pages, component types or mixin types can not be resolved to a class name, by listing the known names.
Document more of the request processing pipeline.
Add StreamResponse (and a basic implementation, TextStreamResponse) and hook in the ability for a component event handler to directly render a response (by returning a StreamResponse).
Interpret the root URL, "/", as a request to render the application's start page.
Added:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/StreamResponse.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TextStreamResponse.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/RootPathDispatcher.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StreamResponseResultProcessor.java
tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/Start.html
Removed:
tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Start.html
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/BlockNotFoundException.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResponseImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/conf.apt
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Start.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/components/Border.html
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/BlockNotFoundException.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/BlockNotFoundException.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/BlockNotFoundException.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/BlockNotFoundException.java Wed Feb 14 18:27:11 2007
@@ -22,6 +22,8 @@
*/
public class BlockNotFoundException extends RuntimeException implements Locatable
{
+ private static final long serialVersionUID = 81221040659940576L;
+
private final Location _location;
public BlockNotFoundException(String message, Location location)
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/StreamResponse.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/StreamResponse.java?view=auto&rev=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/StreamResponse.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/StreamResponse.java Wed Feb 14 18:27:11 2007
@@ -0,0 +1,37 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// 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 org.apache.tapestry;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An alternate response from a component event handler method used to directly provide a stream of
+ * data to be sent to the client, rather than indicating what page to send a render redirect request
+ * to.
+ */
+public interface StreamResponse
+{
+ /** Returns the content type to be reported to the client. */
+ String getContentType();
+
+ /**
+ * Returns the stream of bytes to be sent to the client. The stream will be closed when the end
+ * of the stream is reached. The provided stream will be wrapped in a
+ * {@link BufferedInputStream} for efficiency.
+ */
+ InputStream getStream() throws IOException;
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TextStreamResponse.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TextStreamResponse.java?view=auto&rev=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TextStreamResponse.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TextStreamResponse.java Wed Feb 14 18:27:11 2007
@@ -0,0 +1,49 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// 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 org.apache.tapestry;
+
+import static org.apache.tapestry.ioc.internal.util.Defense.notBlank;
+import static org.apache.tapestry.ioc.internal.util.Defense.notNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class TextStreamResponse implements StreamResponse
+{
+ private final String _contentType;
+
+ private final String _text;
+
+ public TextStreamResponse(final String contentType, final String text)
+ {
+ notBlank(contentType, "contentType");
+ notNull(text, "text");
+
+ _contentType = contentType;
+ _text = text;
+ }
+
+ public String getContentType()
+ {
+ return _contentType;
+ }
+
+ public InputStream getStream() throws IOException
+ {
+ return new ByteArrayInputStream(_text.getBytes());
+ }
+
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java Wed Feb 14 18:27:11 2007
@@ -52,7 +52,7 @@
// structure of Tapestry, there should not be any reader threads while the write thread
// is operating.
- private boolean _rebuild = true;
+ private boolean _needsRebuild = true;
private final Map<String, String> _pageToClassName = newCaseInsensitiveMap();
@@ -107,7 +107,7 @@
/** When the class loader is invalidated, clear any cached page names or component types. */
public synchronized void objectWasInvalidated()
{
- _rebuild = true;
+ _needsRebuild = true;
_pageToClassName.clear();
_componentToClassName.clear();
@@ -118,7 +118,7 @@
private synchronized void rebuild()
{
- if (!_rebuild)
+ if (!_needsRebuild)
return;
rebuild("", _appRootPackage);
@@ -133,7 +133,7 @@
rebuild(folder, packageName);
}
- _rebuild = false;
+ _needsRebuild = false;
}
private void rebuild(String pathPrefix, String rootPackage)
@@ -176,7 +176,18 @@
String result = locate(pageName, _pageToClassName);
if (result == null)
- throw new IllegalArgumentException(ServicesMessages.couldNotResolvePageName(pageName));
+ {
+ // Having trouble tracking this down:
+ System.err.format("Page '%s' not found in %s!\n\n", pageName, _pageToClassName);
+
+ // I have an intuition its a race condition related to the browser asking for
+ // "favicon.ico" but since everything is properly synchronized, I'm not quite sure
+ // how that would happen.
+
+ throw new IllegalArgumentException(ServicesMessages.couldNotResolvePageName(
+ pageName,
+ _pageToClassName.keySet()));
+ }
return result;
}
@@ -191,8 +202,9 @@
String result = locate(componentType, _componentToClassName);
if (result == null)
- throw new IllegalArgumentException(ServicesMessages
- .couldNotResolveComponentType(componentType));
+ throw new IllegalArgumentException(ServicesMessages.couldNotResolveComponentType(
+ componentType,
+ _componentToClassName.keySet()));
return result;
}
@@ -202,7 +214,9 @@
String result = locate(mixinType, _mixinToClassName);
if (result == null)
- throw new IllegalArgumentException(ServicesMessages.couldNotResolveMixinType(mixinType));
+ throw new IllegalArgumentException(ServicesMessages.couldNotResolveMixinType(
+ mixinType,
+ _mixinToClassName.keySet()));
return result;
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java Wed Feb 14 18:27:11 2007
@@ -31,6 +31,7 @@
import org.apache.tapestry.internal.bindings.LiteralBinding;
import org.apache.tapestry.internal.bindings.PropBindingFactory;
import org.apache.tapestry.internal.util.IntegerRange;
+import org.apache.tapestry.ioc.Configuration;
import org.apache.tapestry.ioc.Location;
import org.apache.tapestry.ioc.LogSource;
import org.apache.tapestry.ioc.MappedConfiguration;
@@ -57,6 +58,7 @@
import org.apache.tapestry.services.ComponentClassTransformWorker;
import org.apache.tapestry.services.ComponentMessagesSource;
import org.apache.tapestry.services.Context;
+import org.apache.tapestry.services.InfrastructureContribution;
import org.apache.tapestry.services.MarkupWriterFactory;
import org.apache.tapestry.services.PageRenderInitializer;
import org.apache.tapestry.services.PersistentFieldManager;
@@ -95,19 +97,37 @@
private final RequestPageCache _pageCache;
public InternalModule(@InjectService("ComponentInstantiatorSource")
- ComponentInstantiatorSource componentInstantiatorSource, @InjectService("UpdateListenerHub")
- UpdateListenerHub updateListenerHub, @InjectService("tapestry.ioc.ThreadCleanupHub")
- ThreadCleanupHub threadCleanupHub, @InjectService("ComponentTemplateSource")
+ ComponentInstantiatorSource componentInstantiatorSource,
+
+ @InjectService("UpdateListenerHub")
+ UpdateListenerHub updateListenerHub,
+
+ @InjectService("tapestry.ioc.ThreadCleanupHub")
+ ThreadCleanupHub threadCleanupHub,
+
+ @InjectService("ComponentTemplateSource")
ComponentTemplateSource componentTemplateSource,
- @InjectService("tapestry.ComponentClassResolver")
- ComponentClassResolver componentClassResolver,
- @InjectService("tapestry.ioc.ChainBuilder")
- ChainBuilder chainBuilder, @Inject("infrastructure:Request")
- Request request, @Inject("infrastructure:Response")
- Response response, @InjectService("tapestry.ioc.ThreadLocale")
- ThreadLocale threadLocale, @Inject("infrastructure:RequestGlobals")
- RequestGlobals requestGlobals, @InjectService("RequestPageCache")
- RequestPageCache pageCache)
+
+ @InjectService("tapestry.ComponentClassResolver")
+ ComponentClassResolver componentClassResolver,
+
+ @InjectService("tapestry.ioc.ChainBuilder")
+ ChainBuilder chainBuilder,
+
+ @Inject("infrastructure:Request")
+ Request request,
+
+ @Inject("infrastructure:Response")
+ Response response,
+
+ @InjectService("tapestry.ioc.ThreadLocale")
+ ThreadLocale threadLocale,
+
+ @Inject("infrastructure:RequestGlobals")
+ RequestGlobals requestGlobals,
+
+ @InjectService("RequestPageCache")
+ RequestPageCache pageCache)
{
_componentInstantiatorSource = componentInstantiatorSource;
_updateListenerHub = updateListenerHub;
@@ -277,11 +297,12 @@
* Contributes factory defaults that map be overridden.
*/
@Contribute("tapestry.ioc.FactoryDefaults")
- public void contributeFactoryDefaults(MappedConfiguration<String, String> configuration)
+ public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration)
{
configuration.add("tapestry.file-check-interval", "1000"); // 1 second
configuration.add("tapestry.supported-locales", "en");
configuration.add("tapestry.default-cookie-max-age", "604800"); // One week
+ configuration.add("tapestry.start-page-name", "start");
}
/**
@@ -291,8 +312,11 @@
@Contribute("tapestry.ApplicationInitializer")
public void contributeApplicationInitializerFilters(
OrderedConfiguration<ApplicationInitializerFilter> configuration,
+
@InjectService("tapestry.ioc.PropertyAccess")
- final PropertyAccess propertyAccess, @Inject("infrastructure:TypeCoercer")
+ final PropertyAccess propertyAccess,
+
+ @Inject("infrastructure:TypeCoercer")
final TypeCoercer typeCoercer)
{
ApplicationInitializerFilter setApplicationPackage = new ApplicationInitializerFilter()
@@ -611,5 +635,16 @@
}
};
+ }
+
+ @Contribute("tapestry.Infrastructure")
+ public static void contributeInfrastructure(
+ Configuration<InfrastructureContribution> configuration,
+
+ @InjectService("DefaultRequestExceptionHandler")
+ RequestExceptionHandler defaultRequestExceptionHandler)
+ {
+ configuration.add(new InfrastructureContribution("RequestExceptionHandler",
+ defaultRequestExceptionHandler));
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java Wed Feb 14 18:27:11 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@
public class PageResponseRendererImpl implements PageResponseRenderer
{
private final PageMarkupRenderer _markupRenderer;
-
+
private final MarkupWriterFactory _markupWriterFactory;
public PageResponseRendererImpl(MarkupWriterFactory markupWriterFactory,
@@ -41,10 +41,10 @@
// whatever. Right now its defaulting to plain HTML.
MarkupWriter writer = _markupWriterFactory.newMarkupWriter();
-
+
_markupRenderer.renderPageMarkup(page, writer);
- PrintWriter pw = response.getPrintWriter();
+ PrintWriter pw = response.getPrintWriter("text/html");
writer.toMarkup(pw);
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java Wed Feb 14 18:27:11 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -59,7 +59,12 @@
_response.setDateHeader("Last-Modified", lastModified);
_response.setDateHeader("Expires", lastModified + EXPIRE_DELTA);
- // TODO: content type
+ String contentType = connection.getContentType();
+
+ if (contentType == null)
+ contentType = "application/octet-stream";
+
+ // TODO: if content type is null
InputStream is = null;
@@ -69,7 +74,7 @@
is = new BufferedInputStream(connection.getInputStream());
- OutputStream os = _response.getOutputStream();
+ OutputStream os = _response.getOutputStream(contentType);
byte[] buffer = new byte[_bufferSize];
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResponseImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResponseImpl.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResponseImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResponseImpl.java Wed Feb 14 18:27:11 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,6 +14,8 @@
package org.apache.tapestry.internal.services;
+import static org.apache.tapestry.ioc.internal.util.Defense.notBlank;
+
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
@@ -37,8 +39,12 @@
_response = response;
}
- public PrintWriter getPrintWriter() throws IOException
+ public PrintWriter getPrintWriter(String contentType) throws IOException
{
+ notBlank(contentType, "contentType");
+
+ _response.setContentType(contentType);
+
return _response.getWriter();
}
@@ -57,9 +63,11 @@
_response.sendRedirect(URL);
}
- public OutputStream getOutputStream() throws IOException
+ public OutputStream getOutputStream(String contentType) throws IOException
{
- // TODO: Set content type before getting the stream.
+ notBlank(contentType, "contentType");
+
+ _response.setContentType(contentType);
return _response.getOutputStream();
}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/RootPathDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/RootPathDispatcher.java?view=auto&rev=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/RootPathDispatcher.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/RootPathDispatcher.java Wed Feb 14 18:27:11 2007
@@ -0,0 +1,84 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// 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 org.apache.tapestry.internal.services;
+
+import java.io.IOException;
+
+import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.services.ComponentClassResolver;
+import org.apache.tapestry.services.Dispatcher;
+import org.apache.tapestry.services.Request;
+import org.apache.tapestry.services.Response;
+
+/**
+ * Recognizes a request for the application root (i.e., "/") and handles this the same as a render
+ * request for the "Start" page.
+ */
+public class RootPathDispatcher implements Dispatcher
+{
+ private final ComponentClassResolver _componentClassResolver;
+
+ private final PageLinkHandler _handler;
+
+ private final PageResponseRenderer _renderer;
+
+ private final String _startPageName;
+
+ private final String[] _emptyContext = new String[0];
+
+ public RootPathDispatcher(final ComponentClassResolver componentClassResolver,
+ final PageLinkHandler handler, final PageResponseRenderer renderer,
+ final String startPageName)
+ {
+ _componentClassResolver = componentClassResolver;
+ _handler = handler;
+ _renderer = renderer;
+ _startPageName = startPageName;
+ }
+
+ public boolean dispatch(Request request, final Response response) throws IOException
+ {
+ // Only match the root path
+
+ if (!request.getPath().equals("/"))
+ return false;
+
+ if (_componentClassResolver.isPageName(_startPageName))
+ {
+ PageRenderer renderer = new PageRenderer()
+ {
+ public void renderPage(Page page)
+ {
+ try
+ {
+ _renderer.renderPageResponse(page, response);
+ }
+ catch (IOException ex)
+ {
+ new RuntimeException(ex);
+ }
+
+ }
+ };
+
+ _handler.handle(_startPageName, _emptyContext, renderer);
+
+ return true;
+ }
+
+ return false;
+ }
+
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java Wed Feb 14 18:27:11 2007
@@ -217,19 +217,23 @@
.joinSorted(strategyNames));
}
- static String couldNotResolvePageName(String pageName)
+ static String couldNotResolvePageName(String pageName, Collection<String> pageNames)
{
- return MESSAGES.format("could-not-resolve-page-name", pageName);
+ return MESSAGES.format("could-not-resolve-page-name", pageName, InternalUtils
+ .joinSorted(pageNames));
}
- static String couldNotResolveComponentType(String componentType)
+ static String couldNotResolveComponentType(String componentType,
+ Collection<String> componentTypes)
{
- return MESSAGES.format("could-not-resolve-component-type", componentType);
+ return MESSAGES.format("could-not-resolve-component-type", componentType, InternalUtils
+ .joinSorted(componentTypes));
}
- static String couldNotResolveMixinType(String mixinType)
+ static String couldNotResolveMixinType(String mixinType, Collection<String> mixinTypes)
{
- return MESSAGES.format("could-not-resolve-mixin-type", mixinType);
+ return MESSAGES.format("could-not-resolve-mixin-type", mixinType, InternalUtils
+ .joinSorted(mixinTypes));
}
static String parameterNameMustBeUnique(String parameterName, String parameterValue)
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java Wed Feb 14 18:27:11 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -41,10 +41,17 @@
{
String path = request.getPath();
- URL url = _context.getResource(path);
-
- if (url != null)
- return false;
+ // We are making the questionable assumption that all files to be vended out will contain
+ // an extension (with a dot seperator). Without this, the filter tends to match against
+ // folder names when we don't want it to (especially for the root context path).
+
+ if (path.contains("."))
+ {
+ URL url = _context.getResource(path);
+
+ if (url != null)
+ return false;
+ }
return handler.service(request, response);
}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StreamResponseResultProcessor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StreamResponseResultProcessor.java?view=auto&rev=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StreamResponseResultProcessor.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StreamResponseResultProcessor.java Wed Feb 14 18:27:11 2007
@@ -0,0 +1,76 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// 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 org.apache.tapestry.internal.services;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.tapestry.StreamResponse;
+import org.apache.tapestry.internal.TapestryUtils;
+import org.apache.tapestry.runtime.Component;
+import org.apache.tapestry.services.ActionResponseGenerator;
+import org.apache.tapestry.services.ComponentEventResultProcessor;
+import org.apache.tapestry.services.Response;
+
+public class StreamResponseResultProcessor implements ComponentEventResultProcessor<StreamResponse>
+{
+ private static final int BUFFER_SIZE = 5000;
+
+ public ActionResponseGenerator processComponentEvent(final StreamResponse streamResponse,
+ Component component, final String methodDescripion)
+ {
+ return new ActionResponseGenerator()
+ {
+ public void sendClientResponse(Response response) throws IOException
+ {
+ OutputStream os = null;
+ InputStream is = null;
+
+ try
+ {
+ is = new BufferedInputStream(streamResponse.getStream());
+
+ os = response.getOutputStream(streamResponse.getContentType());
+
+ byte[] buffer = new byte[BUFFER_SIZE];
+
+ while (true)
+ {
+ int length = is.read(buffer, 0, buffer.length);
+ if (length < 0)
+ break;
+
+ os.write(buffer, 0, length);
+ }
+
+ os.close();
+ os = null;
+
+ is.close();
+ is = null;
+ }
+ finally
+ {
+ TapestryUtils.close(is);
+ TapestryUtils.close(os);
+ }
+ }
+
+ };
+ }
+
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java Wed Feb 14 18:27:11 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -29,14 +29,21 @@
/**
* Returns a PrintWriter object to which output may be sent. Invoking flush() on the writer will
* commit the output.
+ *
+ * @param contentType
+ * the MIME content type for the output, typically "text/html"
*/
- PrintWriter getPrintWriter() throws IOException;
+ PrintWriter getPrintWriter(String contentType) throws IOException;
/**
* Returns an OutputStream to which byte-oriented output may be sent. Invoking flush() on the
* stream will commit the output.
+ *
+ * @param contentType
+ * the MIME content type for the output, often "application/octet-stream" or
+ * "text/plain" or one of several others
*/
- OutputStream getOutputStream() throws IOException;
+ OutputStream getOutputStream(String contentType) throws IOException;
/**
* Sends a redirect to the client.
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java Wed Feb 14 18:27:11 2007
@@ -29,6 +29,7 @@
import org.apache.tapestry.Link;
import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.SelectModel;
+import org.apache.tapestry.StreamResponse;
import org.apache.tapestry.Translator;
import org.apache.tapestry.Validator;
import org.apache.tapestry.annotations.AfterRender;
@@ -133,10 +134,12 @@
import org.apache.tapestry.internal.services.ResourceStreamer;
import org.apache.tapestry.internal.services.ResponseImpl;
import org.apache.tapestry.internal.services.RetainWorker;
+import org.apache.tapestry.internal.services.RootPathDispatcher;
import org.apache.tapestry.internal.services.SessionApplicationStatePersistenceStrategy;
import org.apache.tapestry.internal.services.SessionHolder;
import org.apache.tapestry.internal.services.SessionPersistentFieldStrategy;
import org.apache.tapestry.internal.services.StaticFilesFilter;
+import org.apache.tapestry.internal.services.StreamResponseResultProcessor;
import org.apache.tapestry.internal.services.StringResultProcessor;
import org.apache.tapestry.internal.services.SupportsInformalParametersWorker;
import org.apache.tapestry.internal.services.TranslatorDefaultSourceImpl;
@@ -490,12 +493,12 @@
@InjectService("Context")
Context context,
- @InjectService("tapestry.internal.DefaultRequestExceptionHandler")
+ @Inject("infrastructure:RequestExceptionHandler")
final RequestExceptionHandler exceptionHandler)
{
RequestFilter staticFilesFilter = new StaticFilesFilter(context);
- configuration.add("StaticFilesFilter", staticFilesFilter);
+ configuration.add("StaticFiles", staticFilesFilter);
RequestFilter errorFilter = new RequestFilter()
{
@@ -540,7 +543,6 @@
@InjectService("tapestry.ioc.PropertyAccess")
PropertyAccess propertyAccess)
-
{
add(
configuration,
@@ -585,9 +587,27 @@
MappedConfiguration<String, ObjectProvider> configuration,
@InjectService("Infrastructure")
- Infrastructure infrastructure)
+ final Infrastructure infrastructure)
{
- configuration.add("infrastructure", infrastructure.getObjectProvider());
+ // There's a nasty web of dependencies related to Infrastructure; this wrapper class lets us
+ // defer instantiating the Infrastructure implementation just long enough to defuse those
+ // dependencies.
+
+ ObjectProvider wrapper = new ObjectProvider()
+ {
+ public <T> T provide(String expression, Class<T> objectType, ServiceLocator locator)
+ {
+ return infrastructure.getObjectProvider().provide(expression, objectType, locator);
+ }
+ };
+
+ // Or you can defuse the dependency by using @InjectService("foo") instead of
+ // @Inject("service:foo"). The latter requires the MasterObjectProvider, which requires
+ // the Infrastructure, which then fails if any contribution
+ // to infrastructure makes use of @Inject. However, since its likely that end users will try
+ // to do this, the wrapper has been left in place (it does very little harm).
+
+ configuration.add("infrastructure", wrapper);
}
public void contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration,
@@ -607,8 +627,16 @@
ActionLinkHandler actionLinkHandler,
@InjectService("tapestry.ComponentClassResolver")
- ComponentClassResolver componentClassResolver)
+ ComponentClassResolver componentClassResolver,
+
+ @Inject("${tapestry.start-page-name}")
+ String startPageName)
{
+ // Looks for the root path and renders the start page
+
+ configuration.add("RootPath", new RootPathDispatcher(componentClassResolver,
+ pageLinkHandler, _pageResponseRenderer, startPageName), "before:Asset");
+
// This goes first because an asset to be streamed may have an file extension, such as
// ".html", that will confuse the later dispatchers.
@@ -1268,6 +1296,8 @@
configuration.add(String.class, new StringResultProcessor(_requestPageCache, _linkFactory));
configuration.add(Component.class, componentInstanceProcessor);
+
+ configuration.add(StreamResponse.class, new StreamResponseResultProcessor());
}
public ComponentEventResultProcessor buildComponentInstanceResultProcessor(Log log)
@@ -1345,8 +1375,7 @@
* <li>Boolean --> checkbox
* </ul>
*/
- public static void contributeBeanModelSource(
- MappedConfiguration<Class, String> configuration)
+ public static void contributeBeanModelSource(MappedConfiguration<Class, String> configuration)
{
configuration.add(Object.class, "");
configuration.add(String.class, "text");
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties Wed Feb 14 18:27:11 2007
@@ -1,4 +1,4 @@
-# Copyright 2006 The Apache Software Foundation
+# Copyright 2006, 2007 The Apache Software Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -54,9 +54,9 @@
exception-in-method-parameter=Exception in method %s, parameter #%d: %s
component-event-is-aborted=Can not store result from invoking method %s, because an event result value has already been obtained from some other event handler method.
unknown-persistent-field-strategy='%s' is not a defined persistent strategy. Defined stategies: %s.
-could-not-resolve-page-name=Unable to resolve page '%s' to a component class name.
-could-not-resolve-component-type=Unable to resolve component type '%s' to a component class name.
-could-not-resolve-mixin-type=Unable to resolve mixin type '%s' to a component class name.
+could-not-resolve-page-name=Unable to resolve page '%s' to a component class name. Available page names: %s.
+could-not-resolve-component-type=Unable to resolve component type '%s' to a component class name. Available component types: %s.
+could-not-resolve-mixin-type=Unable to resolve mixin type '%s' to a component class name. Available mixin types: %s.
parameter-name-must-be-unique=Parameter names are required to be unique. Parameter '%s' already has the value '%s'.
page-is-dirty=Page %s is dirty, and will be discarded (rather than returned to the page pool).
component-instance-is-not-a-page=Method %s (for component %s) returned component %s, which is not a page component. The page containing the component will render the client response.
Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/conf.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/conf.apt?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/conf.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/conf.apt Wed Feb 14 18:27:11 2007
@@ -5,7 +5,8 @@
Configuring Tapestry
Tapestry runs on top of the standard Java Servlet API. To the servlet container,
- such as Tomcat, Tapestry appears to be a <servlet filter>.
+ such as Tomcat, Tapestry appears as a <servlet filter>. This gives Tapestry great
+ flexibility in matching URLs without requiring lots of configuration inside web.xml.
* web.xml
@@ -48,6 +49,17 @@
In this example, page classes will be stored in the <<<org.example.myapp.pages>>> package (or in sub-packages below).
Likewise, component classes will be stored in the <<<org.example.myapp.components>>> package.
+* Tapestry Requests vs. Container Requests
+
+ The Tapestry filter matches all the requests that apply to Tapestry, and passes the rest off to the
+ servlet container.
+
+ Actual files inside the web application take precedence over Tapestry pages, in situation where there
+ would be a naming conflict.
+
+ Tapestry recognizes the <root URL>, where the servlet path is simply "/", and renders the application page "Start",
+ if it exists.
+
* Tapestry IoC Configuration
Most other configuration occurs inside your application's module builder class. The application module builder
@@ -67,6 +79,14 @@
by contributing to the tapestry.ioc.ApplicationDefaults service configuration, or on the command line
by defining JVM System Properties with the -D command line option.
+ [tapestry.default-cookie-max-age]
+ The default age, in seconds, that cookies created by Tapestry will be kept in the client web browser.
+ The dfault value is equal to one week.
+
+ Primarily, this is used with a cookie that exists
+ to track the preferred user locale.
+
+
[tapestry.file-check-interval]
Time (in milliseconds) between file system checks. During a file system check, only a single thread is active (all others
are blocked) and any files loaded are checked for changes (this is part of {{{reload.html}automatic component reloading}}).
@@ -78,6 +98,9 @@
If no match can be found, the first locale in the list is treated as the default.
The default is (currently) "en".
+
+ [tapestry.start-page-name]
+ The logical name of the start page, the page that is rendered for the <root URL>. This is normally "start".
Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt Wed Feb 14 18:27:11 2007
@@ -27,7 +27,9 @@
This pipeline performs initial processing of the request. It can be extended
by contributing a
{{{../apidocs/org/apache/tapestry/services/HttpServletRequestFilter.html}tapestry.HttpServletRequestFilter}} into
- the tapestry.HttpServletRequestHandler service's configuration.
+ the tapestry.HttpServletRequestHandler service's configuration.'
+
+ Tapestry does not contribute any filters into this pipeline of its own
The terminator for the pipeline does two things:
@@ -48,15 +50,65 @@
Tapestry require access to information in the request, such as query parameters, that information is obtained from the
Request (or Response) objects.
- The pipeline includes two built-in filters. One filter is responsible for {{{reload.html}class and template reloading}}.
+ The pipeline includes a number of built-in filters.
+
+ * tapestry.internal.CheckForUpdates is responsible for {{{reload.html}class and template reloading}}.
+
+ * tapestry.internal.Localization identifies the {{{localization.html}locale for the user}}.
- A second filter detects incoming requests that are for static resources (images, stylesheets, static HTML files, etc.)
- within the context; such requests are
- processed by the servlet container directly.
+ * tapestry.StaticFiles checks for URLs that are for static files (files that exist inside the web context) and aborts
+ the request, so that the servlet container can handle the reuest normally.
+
+ * tapestry.ErrorFilter catches uncaught exceptions from the lower levels of Tapestry and presents the exception report page.
+ This involves the {{{../apidocs/org/apache/tapestry/services/RequestExceptionHandler.html}infrastructure:RequestExceptionHandler}} service,
+ which is responsible for initializing and rendering the
+ {{{../apidocs/org/apache/tapestry/corelib/pages/ExceptionReport.html}core/ExceptionReport}} page.
+
+
+ []
+
+ The terminator for this pipeline stores the Request and the Response into RequestGlobals, then requests that the
+ {{{../apidocs/org/apache/tapestry/services/Dispatcher.html}tapestry.MasterDispatcher}} service figure out how to
+ handle the request (if it is, indeed, a Tapestry request).
- <<TODO: Describe request dispatch, once that is understood.>>
+Master Dispatcher Service
+
+ The MasterDispatcher service is a chain-of-command, aggregating together (in a specific order), several
+ Dispatcher objects. Each Dispatcher is built to recognize and process a particular kind of URL.
+
+* tapestry.RootPath
+
+ As discussed {{{conf.html}elsewhere}}, requests for the context root will instead be treated like render
+ requests for the "start" page.
+
+* tapestry.Asset
+
+ Requests that being with "/assets/" are references to {{{assets.html}asset resources}} that are stored on the classpath, inside the Tapestry JARs
+ (or perhaps inside the JAR for a component library). The contents of the file will be pumped down to the client browser.
+
+* tapestry.PageRender
+
+ Page render requests are requests to render a particular page. Such requests may include additional elements on the path, which will be
+ treated as {{{event.html}activation context}} (generally speaking, the primary key of some related entity object), allowing the page to
+ reconstruct the state it will need to succesfully render itself.
+
+ Page render URLs consist of the logical name of the page plus additional path elements for the activation context. The dispatcher
+ here strips terms off of the path until it finds a known page name. Thus, "/mypage/27" would look first for a page whose name was "mypage/27", then look for
+ a page name "mypage". Assuming the second search was succesful, the page would be activated with the context "27". If no logical page name
+ can be identified, control passes to the next dispatcher.
+
+* tapestry.ComponentEvent
+
+ The component event dispatcher is used to trigger events in components.
+
+ The URL identifies the name of the page, then a series of component ids (the path from the page down to the specific component), then the name of the event to be
+ triggered on the component. The remaining path elements are used as the context for the <event> (not for the page activation, which
+ does not currently apply). For example, "/griddemo.FOO.BAR.action/3" would locate page "griddemo", then component "FOO.BAR", and trigger an event named "action", with
+ the context "3".
+
+ The response from a component event is typically, but not universally, used to send a redirect to the client; the redirect URL is a page render URL
+ to display the response to the event.
- The terminator for this pipeline stores the Request and the Response into RequestGlobals.
RequestGlobals Service
Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt Wed Feb 14 18:27:11 2007
@@ -38,6 +38,13 @@
Progress on Tapestry 5 is really taking off. This space lists some cool new features that have been added
recently.
+ * Component event handlers may now return a {{{apidocs/org/apache/tapestry/StreamResponse.html}StreamResponse}}
+ to directly send a stream to the client web browser (this is intended for components that need to render
+ images, PDF, or other non-page oriented content).
+
+ * The root URL for an application now renders the application's start page (it used to let the
+ servlet container render the static welcome page, if any).
+
* Named-based lookups of messages, resources, etc., are all case-insensitive.
* Fast, smart, fully customizable Grid component for displaying tabular data.
@@ -51,7 +58,7 @@
* Case insensitve URLs. Tapestry no longer cares about the case of the page names and commponent ids it puts
into URLs, and they are now generated in all lower-case for that clean "Web 2.0" look. And they're
- shorter, too!
+ shorter and "prettier", too!
* Initial support for {{{guide/appstate.html}application state objects}}.
@@ -89,31 +96,42 @@
when the form is submitted:
+----+
-@Persist
-private String _userId;
-
-private String _password;
-
-@Component
-private Form _form;
-
-@InjectPage
-private Start _startPage;
-
-@Inject
-private LoginAuthenticator _authenticator;
-
-@OnEvent("submit")
-private Object doLogin()
+public class Login
{
- if (_authenticator.isValidLogin(_userId, _password))
- return _startPage;
-
- // Stay on this page:
-
- _form.recordError("Invalid user name or password.");
-
- return null;
+ @Persist
+ private String _userId;
+
+ private String _password;
+
+ @Component
+ private Form _form;
+
+ @InjectPage
+ private Start _startPage;
+
+ @Inject
+ private LoginAuthenticator _authenticator;
+
+ @OnEvent("submit")
+ private Object doLogin()
+ {
+ if (_authenticator.isValidLogin(_userId, _password))
+ return _startPage;
+
+ // Stay on this page:
+
+ _form.recordError("Invalid user name or password.");
+
+ return null;
+ }
+
+ public String getUserId() { return _userId; }
+
+ public String getPassword() { return _password; }
+
+ public void setUserId(String userId) { _userId = userId; }
+
+ public void setPassword(String password) { _password = password; }
}
+----+
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/Start.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/Start.html?view=auto&rev=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/Start.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/Start.html Wed Feb 14 18:27:11 2007
@@ -0,0 +1,114 @@
+<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+
+ <h1> Tapestry 5 Integration Application 1</h1>
+
+ <table>
+ <tr>
+ <td>
+ <ul>
+ <li>
+ <a t:type="PageLink" page="MerryChristmas">Count Page</a>
+ </li>
+ <li>
+ <a t:type="PageLink" page="InjectDemo">Inject Demo</a>
+ </li>
+ <li>
+ <a t:type="PageLink" page="Countdown">Countdown Page</a>
+ </li>
+ <li>
+ <a t:type="PageLink" page="ParameterConflict">Template Overriden by Class
+ Page</a>
+ </li>
+ <li>
+ <a t:type="PageLink" page="EnvironmentalDemo">Environmental Annotation
+ Useage</a>
+ </li>
+ <li>
+ <a t:type="PageLink" page="expansion">Expansion Page</a>
+ </li>
+ <li>
+ <a href="MissingPage">Missing Page</a> -- Used to test exception reporting </li>
+ <li>
+ <a href="BadTemplate">BadTemplate Page</a> -- More exception reporting </li>
+ <li>
+ <a t:type="PageLink" page="ActionPage">Action Page</a> -- tests fixture for
+ ActionLink component </li>
+ <li>
+ <a t:type="PageLink" page="InstanceMixin">InstanceMixin</a> -- Mixin added
+ to particular component instance </li>
+ <li>
+ <a t:type="PageLink" page="RenderPhaseOrder">RenderPhaseOrder</a> -- Order
+ of operations when invoking render phase methods </li>
+ <li><a t:type="PageLink" page="SimpleForm">SimpleForm</a> -- first pass at
+ writing Form and TextField components </li>
+ <li>
+ <a t:type="PageLink" page="NumberSelect">NumberSelect</a> --
+ passivate/activate page context demo </li>
+ <li>
+ <a t:type="PageLink" page="Localization">Localization</a> -- accessing
+ localized messages from the component catalog </li>
+ <li>
+ <a t:type="PageLink" page="AssetDemo">AssetDemo</a> -- declaring an using
+ Assets </li>
+
+ </ul>
+ </td>
+ <td>
+ <ul>
+ <li>
+ <a t:type="PageLink" page="ExpansionSubclass">ExpansionSubclass</a> --
+ components can inherit templates from base classes </li>
+ <li>
+ <a href="InjectComponentMismatch">InjectComponentMismatch</a> -- check error
+ reporting when @InjectComponent doesn't match the actual field type </li>
+ <li>
+ <a t:type="PageLink" page="ParameterDefault">ParameterDefault</a> --
+ defaulter methods for component parameters </li>
+ <li>
+ <a t:type="PageLink" page="ValidForm">ValidForm</a> -- server-side input
+ validation</li>
+ <li>
+ <a t:type="PageLink" page="AnyDemo">AnyDemo</a> -- test out the Any
+ component </li>
+ <li>
+ <a t:type="PageLink" page="PasswordFieldDemo">PasswordFieldDemo</a> -- test
+ for the PasswordField component </li>
+ <li>
+ <a t:type="PageLink" page="RenderComponentDemo">RenderComponentDemo</a> --
+ components that "nominate" other components to render </li>
+ <li>
+ <a t:type="PageLink" page="BlockDemo">BlockDemo</a> -- use of blocks to
+ control rendering </li>
+ <li>
+ <a t:type="PageLink" page="ToDoListVolatile">ToDo List (Volatile)</a> --
+ Loops and Submit inside Form, volatile mode </li>
+ <li>
+ <a t:type="PageLink" page="ToDoList">ToDo List</a> -- Loops and Submit
+ inside Form using a primary key encoder </li>
+ <li>
+ <a t:type="PageLink" page="FlashDemo">FlashDemo</a> -- demonstrate "flash"
+ persistence </li>
+ <li>
+ <a t:type="PageLink" page="beaneditordemo">BeanEditor Demo</a> --
+ demonstrate the BeanEditor mega-component </li>
+ <li>
+ <a t:type="PageLink" page="pageloadeddemo">PageLoaded Demo</a> -- shows that
+ page lifecycle methods are invoked </li>
+ <li>
+ <a t:type="PageLink" page="griddemo">Grid Demo</a> -- default Grid component </li>
+ <li>
+ <a t:type="PageLink" page="nullgrid">Null Grid</a> -- handling of null
+ source for Grid </li>
+ <li>
+ <a t:type="PageLink" page="gridenumdemo">Grid Enum Demo</a> -- handling of
+ enum types in the Grid </li>
+ <li>
+ <a t:type="ActionLink" t:id="textStreamResponse">Text Stream Response</a> --
+ component event that directly returns a stream of character (rather than a
+ redirect) </li>
+ </ul>
+ </td>
+ </tr>
+ </table>
+
+</html>
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Wed Feb 14 18:27:11 2007
@@ -102,28 +102,6 @@
}
@Test
- public void basic_output() throws Exception
- {
- _selenium.open(BASE_URL);
-
- clickAndWait("link=Start Page");
-
- // This comes from the Border cmponent's template
-
- assertTrue(_selenium.getTitle().contains("Tapestry"));
-
- // Text from Start.html
-
- assertTextPresent("First Tapestry 5 Page");
-
- // This is text passed from Start.html to Output as a parameter
-
- assertTextPresent("we have basic parameters working");
-
- assertSourcePresent("<!-- my comment -->");
- }
-
- @Test
public void basic_parameters() throws Exception
{
@@ -870,11 +848,37 @@
}
@Test
- public void null_grid()
+ public void stream_response() throws Exception
{
_selenium.open(BASE_URL);
+
+ clickAndWait("link=Text Stream Response");
+
+ assertText("//body", "Success!");
+ }
+
+ @Test
+ public void null_grid() throws Exception
+ {
+ // Been having problems with very spurious failures of this test. Troubling, and it has
+ // repairman
+ // syndrome; only happens during a full suite, where I can't pick out the problem. These
+ // calls to System.error
+ // seem to have "fixed" it. I think TestNG may be running null_grid() first.
+
+ System.err.println("****\n\n\nNULL GRID START\n\n****\n\n");
+
+ _selenium.open(BASE_URL);
+
+ // Let's see if sleeping for a half second is enough.
+
+ Thread.sleep(5000);
+
clickAndWait("link=Null Grid");
assertTextPresent("There is no data to display.");
+
+ System.err.println("****\n\n\nNULL GRID END\n\n****\n\n");
}
+
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Start.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Start.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Start.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Start.java Wed Feb 14 18:27:11 2007
@@ -14,9 +14,17 @@
package org.apache.tapestry.integration.app1.pages;
+import org.apache.tapestry.TextStreamResponse;
+
/**
* Have to start somewhere!
*/
public class Start
{
+ Object onActionFromTextStreamResponse()
+ {
+ String text = "<html><body>Success!</body></html>";
+
+ return new TextStreamResponse("text/html", text);
+ }
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java Wed Feb 14 18:27:11 2007
@@ -425,9 +425,8 @@
}
catch (IllegalArgumentException ex)
{
- assertEquals(
- ex.getMessage(),
- "Unable to resolve page 'lib/deep/DeepPage' to a component class name.");
+ assertTrue(ex.getMessage().contains(
+ "Unable to resolve page 'lib/deep/DeepPage' to a component class name."));
}
verify();
@@ -512,9 +511,8 @@
}
catch (IllegalArgumentException ex)
{
- assertEquals(
- ex.getMessage(),
- "Unable to resolve mixin type 'SimpleMixin' to a component class name.");
+ assertTrue(ex.getMessage().contains(
+ "Unable to resolve mixin type 'SimpleMixin' to a component class name."));
}
verify();
@@ -542,9 +540,10 @@
}
catch (IllegalArgumentException ex)
{
- assertEquals(
- ex.getMessage(),
- "Unable to resolve component type 'SimpleComponent' to a component class name.");
+ assertTrue(ex
+ .getMessage()
+ .contains(
+ "Unable to resolve component type 'SimpleComponent' to a component class name."));
}
verify();
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/components/Border.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/components/Border.html?view=diff&rev=507781&r1=507780&r2=507781
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/components/Border.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/components/Border.html Wed Feb 14 18:27:11 2007
@@ -14,7 +14,7 @@
<p>
- <a href="/index.html">Back to index</a>
+ <a t:type="PageLink" page="Start">Back to index</a>
</p>
</body>