All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.directory.sdk.common.api.VelocityContextProvider Maven / Gradle / Ivy

Go to download

The UnboundID Server SDK is a library that may be used to develop various types of extensions to Ping Identity server products, including the Directory Server, Directory Proxy Server, Data Sync Server, Data Metrics Server, and Data Governance Broker.

There is a newer version: 6.2.0.0
Show newest version
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * docs/licenses/cddl.txt
 * or http://www.opensource.org/licenses/cddl1.php.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * docs/licenses/cddl.txt.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2013-2024 Ping Identity Corporation
 */
package com.unboundid.directory.sdk.common.api;


import com.unboundid.directory.sdk.broker.internal.BrokerExtension;
import com.unboundid.directory.sdk.common.config.VelocityContextProviderConfig;
import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
import com.unboundid.directory.sdk.common.internal.Reconfigurable;
import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
import com.unboundid.directory.sdk.common.types.ServerContext;
import com.unboundid.directory.sdk.common.types.VelocityContext;
import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
import com.unboundid.directory.sdk.metrics.internal.MetricsEngineExtension;
import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.util.Extensible;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

import static com.unboundid.directory.sdk.common.config
        .VelocityContextProviderConfig.ObjectScope;
import static com.unboundid.directory.sdk.common.config
  .VelocityContextProviderConfig.ObjectScope.APPLICATION;
import static com.unboundid.directory.sdk.common.config
  .VelocityContextProviderConfig.ObjectScope.REQUEST;
import static com.unboundid.directory.sdk.common.config
  .VelocityContextProviderConfig.ObjectScope.SESSION;


/**
 * This class defines an API that must be implemented by extensions which
 * contribute content to server pages authored as Velocity templates.
 * These pages are rendered by the Velocity HTTP Servlet Extension included
 * with the server. During rendering of a Velocity page, the template is merged
 * with a 'context' that provides values for variables, properties, and method
 * references in the template.
 * 

* A context provider can be restricted to contributing content for certain * pages by specifying one or more included or excluded views names. A view * name is the URL request path to a template that does not include the * HTTP servlet extension's base context path, nor a starting path separator. * So for example if a template was accessible by the URL * http://localhost:8080/view/path/to/template the view name would be * 'path/to/template'. *

* In addition to contributing content for views, a context provider can also * be configured to add header fields to HTTP responses using the * request-header configuration property. Header field values specified the * by a context provider override values for identical fields names for which * the Velocity HTTP Servlet Extension is configured to add to responses. *

* Context providers are restricted to servicing requests for the configured * set of HTTP operations. By default, only the HTTP GET method is enabled * though this can be changed by updating the http-method configuration * property. Implementations should abide by the conventions mandated by the * HTTP method specification. For example, an implementation that handles the * GET method should be restricted to retrieval only and not introduce any * persistent side-effects that would change the state of the server. *

Configuring Velocity Context Providers

* In order to configure a Velocity context provider created using this API, * use a command like: *
 *      dsconfig create-velocity-context-provider \
 *           --extension-name "{extension}" \
 *           --provider-name "{provider}" \
 *           --type third-party \
 *           --set enabled:true \
 *           --set "extension-class:{class-name}" \
 *           --set "extension-argument:{name=value}"
 * 
* where "{extension}" is the name of the Velocity HTTP servlet * extension, ("Velocity" by default) * "{provider}" is the name to use for the Velocity context provider * instance, "{class-name}" is the fully-qualified name of the Java * class that extends * {@code com.unboundid.directory.sdk.common.api.VelocityContextProvider}, * and "{name=value}" represents name-value pairs for any arguments to * provide to the virtual attribute provider. If multiple arguments should be * provided to the virtual attribute provider, then the * "--set extension-argument:{name=value}" option should be * provided multiple times. */ @Extensible() @DirectoryServerExtension() @DirectoryProxyServerExtension(appliesToLocalContent = true, appliesToRemoteContent = false) @SynchronizationServerExtension(appliesToLocalContent = true, appliesToSynchronizedContent = false) @MetricsEngineExtension() @BrokerExtension() @ThreadSafety(level = ThreadSafetyLevel.INTERFACE_THREADSAFE) public abstract class VelocityContextProvider implements UnboundIDExtension, Reconfigurable, ExampleUsageProvider { // The current configuration. private VelocityContextProviderConfig config; /** * {@inheritDoc} */ public abstract String getExtensionName(); /** * {@inheritDoc} */ public abstract String[] getExtensionDescription(); /** * {@inheritDoc} */ public void defineConfigArguments(final ArgumentParser parser) throws ArgumentException { // No arguments will be allowed by default. } /** * Initializes this Velocity context provider. * * @param serverContext A handle to the server context for the server in * which this extension is running. * @param config The general configuration for this Velocity context * provider. * @param parser The argument parser which has been initialized from * the configuration for this Velocity context * provider. * @throws LDAPException If a problem occurs while initializing this context * provider. */ public void initializeVelocityContextProvider( final ServerContext serverContext, final VelocityContextProviderConfig config, final ArgumentParser parser) throws LDAPException { this.config = config; } /** * {@inheritDoc} */ public boolean isConfigurationAcceptable( final VelocityContextProviderConfig config, final ArgumentParser parser, final List unacceptableReasons) { // No extended validation will be performed by default. return true; } /** * {@inheritDoc} */ public ResultCode applyConfiguration( final VelocityContextProviderConfig config, final ArgumentParser parser, final List adminActionsRequired, final List messages) { // By default, no configuration changes will be applied. If there are any // arguments, then add an admin action message indicating that the extension // needs to be restarted for any changes to take effect. if (!parser.getNamedArguments().isEmpty()) { adminActionsRequired.add( "No configuration change has actually been applied. The new " + "configuration will not take effect until this Velocity " + "context provider is disabled and re-enabled or until the " + "server is restarted."); } return ResultCode.SUCCESS; } /** * Performs any cleanup which may be necessary when this virtual attribute * provider is to be taken out of service. */ public void finalizeVelocityContextProvider() { // No implementation is required. } /** * Handle an HTTP DELETE request. Implementations should be idempotent in * the sense that the side-effects of a single call to this method are the * same as N > 0 identical requests. * * @param context to update. * @param request for the view implemented by a template. * @param response to the client. * * @throws IOException if the provider has a problem related to processing * the response such as sending an error to the client. */ public void handleDelete(final VelocityContext context, final HttpServletRequest request, final HttpServletResponse response) throws IOException { response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } /** * Handle an HTTP GET request. Implementations should be restricted to * retrieval operations only, ensuring there are no persistent side-effects * generated by the server as a result of this method being called. * * @param context to update. * @param request for the view implemented by a template. * @param response to the client. * * @throws IOException if the provider has a problem related to processing * the response such as sending an error to the client. */ public void handleGet(final VelocityContext context, final HttpServletRequest request, final HttpServletResponse response) throws IOException { // Do not respond with an error to avoid breaking existing implementations. } /** * Handle an HTTP HEAD request. Implementations should be restricted to * retrieval operations only, ensuring there are no persistent side-effects * generated by the server as a result of this method being called. * * @param context to update. * @param request for the view implemented by a template. * @param response to the client. * * @throws IOException if the provider has a problem related to processing * the response such as sending an error to the client. */ public void handleHead(final VelocityContext context, final HttpServletRequest request, final HttpServletResponse response) throws IOException { response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } /** * Handle an HTTP OPTIONS request. Implementations should ensure there * are no persistent side-effects generated by the server as a result of this * method being called. * * @param context to update. * @param request for the view implemented by a template. * @param response to the client. * * @throws IOException if the provider has a problem related to processing * the response such as sending an error to the client. */ public void handleOptions(final VelocityContext context, final HttpServletRequest request, final HttpServletResponse response) throws IOException { response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } /** * Handle an HTTP PATCH request. * * @param context to update. * @param request for the view implemented by a template. * @param response to the client. * * @throws IOException if the provider has a problem related to processing * the response such as sending an error to the client. */ public void handlePatch(final VelocityContext context, final HttpServletRequest request, final HttpServletResponse response) throws IOException { response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } /** * Handle an HTTP POST request. * * @param context to update. * @param request for the view implemented by a template. * @param response to the client. * * @throws IOException if the provider has a problem related to processing * the response such as sending an error to the client. */ public void handlePost(final VelocityContext context, final HttpServletRequest request, final HttpServletResponse response) throws IOException { // Do not respond with an error to avoid breaking existing implementations. } /** * Handle an HTTP PUT request. Implementations should be idempotent in * the sense that the side-effects of a single call to this method are the * same as N > 0 identical requests. * * @param context to update. * @param request for the view implemented by a template. * @param response to the client. * * @throws IOException if the provider has a problem related to processing * the response such as sending an error to the client. */ public void handlePut(final VelocityContext context, final HttpServletRequest request, final HttpServletResponse response) throws IOException { response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } /** * Handle an HTTP TRACE request. Implementations should ensure there * are no persistent side-effects generated by the server as a result of this * method being called. * * @param context to update. * @param request for the view implemented by a template. * @param response to the client. * * @throws IOException if the provider has a problem related to processing * the response such as sending an error to the client. */ public void handleTrace(final VelocityContext context, final HttpServletRequest request, final HttpServletResponse response) throws IOException { response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } /** * Handle an HTTP method not already handled by one of the other * {@code handleXXX} methods. Implementations should check the value * of the request's {@code getMethod()} method and take whatever action is * necessary to fulfill the request before updating the context. Unexpected * HTTP methods should result in the client sending an HTTP 405 Method Not * Allowed response. * * @param context to update. * @param request for the view implemented by a template. * @param response to the client. * * @throws IOException if the provider has a problem related to processing * the response such as sending an error to the client. */ public void handleAdditionalMethod(final VelocityContext context, final HttpServletRequest request, final HttpServletResponse response) throws IOException { response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } /** * This method is called following a call to one of the {@code handleXXX} * methods and may be used for logic that is independent of the HTTP operation * requested. HTTP method-specific code such as request attribute or form * data processing should be restricted to the appropriate {@code handleXXX} * method. * * @param context to update. * @param request for the view implemented by a template. * @param response to the client. * * @throws IOException if the provider has a problem related to processing * the response such as sending an error to the client. */ public void updateContext(final VelocityContext context, final HttpServletRequest request, final HttpServletResponse response) throws IOException { // No implementation. } /** * Gets an object from the current user session or servlet context * depending on the object scope currently configured for this provider. * This method can be used as a convenience for providers the maintain * a set of context objects for a particular scope. * * @param the type of object to return. If an object exists in * the current scope with the given name but is not of type * T this method returns {@code null} * * @param name of the object. * @param request current user request. * * @return the named object or {@code null} if no object exists by the * provided name or an input parameter is (@code null}. */ protected T getNamedObject(final String name, final HttpServletRequest request) { T object = null; if (this.config != null) { object = getNamedObject(name, request, config.getObjectScope()); } return object; } /** * Stores an object in current user request, session or servlet context * depending on the object scope currently configured for this provider. * This method can be used as a convenience for providers the maintain * a set of context objects for a particular scope. * * @param name of the object. * @param object to store. * @param request current user request. */ protected void setNamedObject(final String name, final Object object, final HttpServletRequest request) { if (this.config != null) { setNamedObject(name, object, request, config.getObjectScope()); } } /** * Gets an object from the current user session or servlet context * depending on the object scope currently configured for this provider. * This method can be used as a convenience for providers the maintain * a set of context objects for a particular scope. * * @param the type of object to return. If an object exists in * the current scope with the given name but is not of type * T this method returns {@code null} * * @param name of the object. * @param request current user request. * @param scope from which to retrieve the object. * @return the named object or {@code null} if no object exists by the * provided name or an input parameter is (@code null}. */ @SuppressWarnings("unchecked") public static T getNamedObject(final String name, final HttpServletRequest request, final ObjectScope scope) { T object = null; Object o = null; if (name != null && request != null) { if (REQUEST.equals(scope)) { o = request.getAttribute(name); } else if (SESSION.equals(scope)) { HttpSession session = request.getSession(false); if (session != null) { o = session.getAttribute(name); } } else if (APPLICATION.equals(scope)) { o = request.getServletContext().getAttribute(name); } } try { object = (T) o; } catch (ClassCastException cce) { // ignore } return object; } /** * Stores an object in current user request, session or servlet context * depending on the object scope currently configured for this provider. * This method can be used as a convenience for providers the maintain * a set of context objects for a particular scope. * * @param name of the object. * @param object to store. * @param request current user request. * @param scope in which to set the object. */ public static void setNamedObject(final String name, final Object object, final HttpServletRequest request, final ObjectScope scope) { if (scope != null && request != null && name != null) { if (REQUEST.equals(scope)) { request.setAttribute(name, object); } else if (SESSION.equals(scope)) { HttpSession session = request.getSession(true); session.setAttribute(name, object); } else if (APPLICATION.equals(scope)) { request.getServletContext().setAttribute(name, object); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy