Skip to content

Commit

Permalink
TAP5-2696: REST support
Browse files Browse the repository at this point in the history
TAP5-2696: fixing TapestryHttpModule import

Bumping version to 5.8.0 due to major improvement added (REST)

TAP5-2696: OpenAPI viewer, OpenAPI definition dispatcher

plus a few JavaDoc fixes

TAP5-2696: generating OpenAPI for path and query parameters

TAP5-2696: adding missing commons-io dependency to tapestry-http

TAP5-2696: some REST code adjustments

TAP5-2696: fixing NPE in OpenAPI generation

when a superclass has no REST event handler methods

TAP5-2696: adding @ActivactionContextParameter

TAP5-2696: caching in OpenAPI dispatcher when production mode is on

TAP5-2696: moving some classes to RESt-specific packages

TAP5-2696: removing OpenAPI description validation and .map assets

TAP5-2696: bunch of changes.

Added MappedEntitiesService
Added OpenAPI base path configuration symbol
Added @RestInfo with information about produced and consumed MIME types
to OpenAPI description, plus the expected return type of event handler
methods
Added OpenApiTypeDescriber
Added HttpStatus to be a more generic version of HttpError

TAP5-2696: fixing misplaced code in tapestry-openapi-viewer

TAP5-2696: better HttpStatus and OpenAPI viewer styling

TAP5-2696: changing the root tapestry-openapi-viewer package

TAP5-2696: adding tapestry-rest-jackson

TAP5-2696: adding some methods to HttpStatus

TAP5-2696: generating descriptions of request bodies, plus some fixes

TAP5-2696: fixing JSON mime type in test code

TAP5-2696: fixing JavaDoc and JSON content type

TAP5-2696: fixing more JavaDoc

TAP5-2696: fixing MiscTests.static_activation_context_value

TAP5-2696: fixing compilation error
  • Loading branch information
thiagohp committed Dec 11, 2021
1 parent 32353fc commit 470f0ea
Show file tree
Hide file tree
Showing 92 changed files with 5,435 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ gradle-app.setting
*~
\#*
/.metadata/
docs/*
docs/
6 changes: 4 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ project.ext.versions = [
hibernate: "5.4.32.Final",
slf4j: "1.7.25",
geb: "2.0",
selenium: "3.141.59"
selenium: "3.141.59",
jackson: "2.13.0",
jsonschemaGenerator: "4.20.0"
]

ext.continuousIntegrationBuild = Boolean.getBoolean("ci")
Expand All @@ -33,7 +35,7 @@ project.version = tapestryVersion()

def tapestryVersion() {

def major = "5.7.4"
def major = "5.8.0"
def minor = ""

// When building on the CI server, make sure -SNAPSHOT is appended, as it is a nightly build.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.apache.tapestry5.commons.services.CoercionTuple;
import org.apache.tapestry5.commons.services.TypeCoercer;
import org.apache.tapestry5.commons.util.AvailableValues;
import org.apache.tapestry5.commons.util.CoercionFailedException;
import org.apache.tapestry5.commons.util.CoercionNotFoundException;
import org.apache.tapestry5.commons.util.CollectionFactory;
import org.apache.tapestry5.commons.util.StringToEnumCoercion;
import org.apache.tapestry5.commons.util.UnknownValueException;
Expand Down Expand Up @@ -76,7 +78,7 @@ Object coerce(Object input)
return type.cast(c.coerce(input));
} catch (Exception ex)
{
throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
throw new CoercionFailedException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
}
}

Expand Down Expand Up @@ -338,8 +340,8 @@ private Coercion findOrCreateCoercion(Class sourceType, Class targetType)
// Not found anywhere. Identify the source and target type and a (sorted) list of
// all the known coercions.

throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.",
sourceType.getName(), targetType.getName()), buildCoercionCatalog());
throw new CoercionNotFoundException(String.format("Could not find a coercion from type %s to type %s.",
sourceType.getName(), targetType.getName()), buildCoercionCatalog(), sourceType, targetType);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2021 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.tapestry5.commons.util;

import org.apache.tapestry5.commons.internal.util.TapestryException;
import org.apache.tapestry5.commons.services.Coercion;

/**
* Exception used when a {@link Coercion} throws an exception while
* trying to coerce a value.
*
* @since 5.8.0
*/
public class CoercionFailedException extends TapestryException
{

private static final long serialVersionUID = 1L;

public CoercionFailedException(String message, Throwable cause)
{
super(message, cause);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2021 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.tapestry5.commons.util;

import org.apache.tapestry5.commons.services.TypeCoercer;

/**
* Exception used when {@link TypeCoercer} doesn't find a coercion from a type to another.
*
* @since 5.8.0
*/
public class CoercionNotFoundException extends UnknownValueException
{

private static final long serialVersionUID = 1L;

final private Class<?> sourceType;

final private Class<?> targetType;

public CoercionNotFoundException(String message, AvailableValues availableValues, Class<?> sourceType, Class<?> targetType)
{
super(message, availableValues);
this.sourceType = sourceType;
this.targetType = targetType;
}

/**
* Returns the source type.
*/
public Class<?> getSourceType() {
return sourceType;
}


/**
* Returns the target type.
*/
public Class<?> getTargetType() {
return targetType;
}

}
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ include "tapestry-test-data", 'tapestry-internal-test', "tapestry-ioc-junit"
include "tapestry-webresources", "tapestry-runner", "tapestry-test-constants"
include "tapestry-ioc-jcache", "beanmodel", "commons", "genericsresolver-guava", "tapestry-version-migrator"
// include "tapestry-cdi"
include "tapestry-spock"
include "tapestry-spock", "tapestry-openapi-viewer", "tapestry-rest-jackson"
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.apache.tapestry5;

import org.apache.tapestry5.http.Link;
import org.apache.tapestry5.internal.InternalConstants;
import org.apache.tapestry5.ioc.util.IdAllocator;
import org.apache.tapestry5.services.ComponentEventRequestParameters;
import org.apache.tapestry5.services.ComponentSource;
Expand Down Expand Up @@ -213,15 +214,15 @@ public class EventConstants
public static final String PREALLOCATE_FORM_CONTROL_NAMES = "preallocateFormControlNames";

/**
* Event triggered by the {@link org.apache.tapestry5.corelib.components.Tree}
* Event triggered by the {@link org.apache.tapestry5.corelib.components.Tree}
* component when a leaf node is selected.
*
* @since 5.3
*/
public static final String NODE_SELECTED = "nodeSelected";

/**
* Event triggered by the {@link org.apache.tapestry5.corelib.components.Tree}
* Event triggered by the {@link org.apache.tapestry5.corelib.components.Tree}
* component when a leaf node is unselected.
*
* @since 5.3
Expand All @@ -235,4 +236,47 @@ public class EventConstants
* @since 5.3
*/
public static final String REFRESH = "refresh";

/**
* Event triggered when a page receives an HTTP GET request.
* Handling this event creates a REST endpoint.
* @since 5.8.0
*/
public static final String HTTP_GET = InternalConstants.HTTP_METHOD_EVENT_PREFIX + "Get";

/**
* Event triggered when a page receives an HTTP POST request.
* Handling this event creates a REST endpoint.
* @since 5.8.0
*/
public static final String HTTP_POST = InternalConstants.HTTP_METHOD_EVENT_PREFIX + "Post";

/**
* Event triggered when a page receives an HTTP DELETE request.
* Handling this event creates a REST endpoint.
* @since 5.8.0
*/
public static final String HTTP_DELETE = InternalConstants.HTTP_METHOD_EVENT_PREFIX + "Delete";

/**
* Event triggered when a page receives an HTTP PUT request.
* Handling this event creates a REST endpoint.
* @since 5.8.0
*/
public static final String HTTP_PUT = InternalConstants.HTTP_METHOD_EVENT_PREFIX + "Put";

/**
* Event triggered when a page receives an HTTP HEAD request.
* Handling this event creates a REST endpoint.
* @since 5.8.0
*/
public static final String HTTP_HEAD = InternalConstants.HTTP_METHOD_EVENT_PREFIX + "Head";

/**
* Event triggered when a page receives an HTTP PATCH request.
* Handling this event creates a REST endpoint.
* @since 5.8.0
*/
public static final String HTTP_PATCH = InternalConstants.HTTP_METHOD_EVENT_PREFIX + "Patch";

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@
import org.apache.tapestry5.corelib.components.Errors;
import org.apache.tapestry5.corelib.mixins.FormGroup;
import org.apache.tapestry5.http.TapestryHttpSymbolConstants;
import org.apache.tapestry5.http.services.BaseURLSource;
import org.apache.tapestry5.internal.services.AssetDispatcher;
import org.apache.tapestry5.internal.services.rest.DefaultOpenApiDescriptionGenerator;
import org.apache.tapestry5.modules.NoBootstrapModule;
import org.apache.tapestry5.services.Html5Support;
import org.apache.tapestry5.services.assets.AssetPathConstructor;
import org.apache.tapestry5.services.assets.ResourceMinimizer;
import org.apache.tapestry5.services.compatibility.Trait;
import org.apache.tapestry5.services.javascript.JavaScriptStack;
import org.apache.tapestry5.services.rest.OpenApiDescriptionGenerator;

/**
* Defines the names of symbols used to configure Tapestry.
Expand Down Expand Up @@ -643,4 +646,70 @@ public class SymbolConstants
* @since 5.4
*/
public static final String PRELOADER_MODE = "tapestry.page-preload-mode";

/**
* Defines the OpenAPI version to be used in the generated OpenAPI description.
* Default value is <code>3.0.0</code>.
* @see DefaultOpenApiDescriptionGenerator
* @see OpenApiDescriptionGenerator
* @since 5.8.0
*/
public static final String OPENAPI_VERSION = "tapestry.openapi-version";

/**
* Defines the title of this application in the generated OpenAPI description. No default value is provided.
* @see DefaultOpenApiDescriptionGenerator
* @see OpenApiDescriptionGenerator
* @since 5.8.0
*/
public static final String OPENAPI_TITLE = "tapestry.openapi-title";

/**
* Defines the description of this application in the generated OpenAPI description.
* No default value is provided.
* @see DefaultOpenApiDescriptionGenerator
* @see OpenApiDescriptionGenerator
* @since 5.8.0
*/
public static final String OPENAPI_DESCRIPTION = "tapestry.openapi-description";

/**
* Defines the version of this application in the generated OpenAPI description (i.e. info/version).
* No default value is provided.
* @see DefaultOpenApiDescriptionGenerator
* @see OpenApiDescriptionGenerator
* @since 5.8.0
*/
public static final String OPENAPI_APPLICATION_VERSION = "tapestry.openapi-application-version";

/**
* Defines whether the OpenAPI description file of this application's REST endpoints should be
* published or not. The default value is <code>false</code>.
* @see OpenApiDescriptionGenerator
* @see #OPENAPI_DESCRIPTION_PATH
* @since 5.8.0
*/
public static final String PUBLISH_OPENAPI_DEFINITON = "tapestry.publish-openapi-description";

/**
* Defines the path the OpenAPI description file of this application's REST endpoints will be
* published. It should start with a slash. The default value is <code>openapi.json</code>.
* Default value is <code>/openapi.json</code>.
* The description will only be published if {{@link #PUBLISH_OPENAPI_DEFINITON} is set to
* <code>true</code>.
* @see OpenApiDescriptionGenerator
* @since 5.8.0
*/
public static final String OPENAPI_DESCRIPTION_PATH = "tapestry.openapi-description-path";

/**
* Defines a base path to the generated OpenAPI description relative to the application
* URL as defined by {@link BaseURLSource#getBaseURL(boolean)}. It should be either
* the empty string, meaning there's no base path, or a string starting and ending
* with a slash. Default value is "/" (without the quotes)
* @see OpenApiDescriptionGenerator
* @since 5.8.0
*/
public static final String OPENAPI_BASE_PATH = "tapestry.openapi-base-path";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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.tapestry5.annotations;

import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.apache.tapestry5.ioc.annotations.AnnotationUseContext.PAGE;
import static org.apache.tapestry5.ioc.annotations.AnnotationUseContext.COMPONENT;
import static org.apache.tapestry5.ioc.annotations.AnnotationUseContext.MIXIN;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import org.apache.tapestry5.ioc.annotations.UseWith;

/**
* Annotation that may be placed on parameters of event handler methods to define their names
* in OpenAPI description. This is <em>not</em> needed for an event handler parameter to be
* a parameter in a REST endpoint event handler method.
*
* @since 5.8.0
*/
@Target(
{ PARAMETER })
@Retention(RUNTIME)
@Documented
@UseWith(
{ PAGE, COMPONENT, MIXIN })
public @interface ActivationContextParameter
{
/**
* The name to be used for this parameter in the OpenAPI description.
*/
String value();
}
Loading

0 comments on commit 470f0ea

Please sign in to comment.