getAttributeNames();
/**
* Remove the attribute.
*
* @param name the name.
*/
void removeAttribute(String name);
/**
* Set the attribute.
*
* @param name the name.
* @param value the value.
*/
void setAttribute(String name, Object value);
/**
* Checks if this manager has the given attribute
* @param name the name of the attribute to check for
* @return true if this manager contains the attribute, false otherwise
*/
default boolean containsAttribute(String name) {
return getAttribute(name) != null;
}
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/AuthenticatedIdentity.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import java.security.Principal;
import java.util.Set;
/**
* This interface is implemented by classes that represent the current authenticated identity.
*
*
* What current means here is context dependent. In a Jakarta Servlet application this refers
* to the caller (user) details during a single HTTP request.
*
* @author Arjan Tijms
*
*/
public interface AuthenticatedIdentity extends Principal {
@Override
default String getName() {
if (getCallerPrincipal() == null) {
return null;
}
return getCallerPrincipal().getName();
}
/**
* Returns the caller principal, which represents the primary name of the calling entity (aka the "caller")
* to a server.
*
* @return the caller principal, or null if authentication has not (yet) completed successfully.
*/
Principal getCallerPrincipal();
/**
* The groups the caller is in.
*
*
* If group to role mapping is not active (the default) groups are equal to roles.
*
* @return the set of groups the caller is in, never null.
*/
Set getGroups();
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/CurrentRequestHolder.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.http.HttpServletRequest;
/**
* A holder that references the current HttpServletRequest in the request processing
* pipeline.
*
*
* This structure allows the runtime to set what constitutes this current at any given
* time.
*
* @author Arjan Tijms
*
*/
public interface CurrentRequestHolder {
/**
* The request attribute under a holder implementation is stored in the request
*/
String CURRENT_REQUEST_ATTRIBUTE = CurrentRequestHolder.class.getName();
/**
* Gets the current HttpServletRequest
*
* @param the actual implementation of the current HttpServletRequest
* @return the current HttpServletRequest
*/
T getRequest();
/**
* Sets the current HttpServletRequest
*
* @param request the current HttpServletRequest
*/
void setRequest(HttpServletRequest request);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/DispatcherManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.RequestDispatcher;
/**
* The DispatcherManager API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface DispatcherManager {
/**
* Get the named request dispatcher.
*
* @param name the name.
* @return the request dispatcher.
*/
RequestDispatcher getNamedDispatcher(String name);
/**
* Set the web application.
*
* @param webApplication the web application.
*/
void setWebApplication(WebApplication webApplication);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/ErrorPageManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.http.HttpServletResponse;
/**
* The ErrorPageManager API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface ErrorPageManager {
/**
* Add an error page.
*
* @param statusCode the status code.
* @param page the page.
*/
void addErrorPage(int statusCode, String page);
/**
* Add an error page.
*
* @param throwableClassName the throwable class name.
* @param page the page.
*/
void addErrorPage(String throwableClassName, String page);
/**
* {@return the error page}
*
* @param throwable the throwable.
* @param response the HTTP servlet response.
*/
String getErrorPage(Throwable throwable, HttpServletResponse response);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/FilterEnvironment.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.FilterRegistration.Dynamic;
import jakarta.servlet.ServletException;
/**
* The environment of a Filter.
*
* @author Manfred Riem (mriem@manorrock.com)
* @author Arjan Tijms
*/
public interface FilterEnvironment extends Dynamic, FilterConfig {
/**
* Defines the UNAVAILABLE constant.
*/
int UNAVAILABLE = -1;
/**
* {@return the filter}
*/
Filter getFilter();
/**
* Initialize the filter.
*
* @throws ServletException when a servlet error occurs.
*/
void initialize() throws ServletException;
/**
* Set the class name.
*
* @param className the class name.
*/
void setClassName(String className);
/**
* Set the filter name.
*
* @param filterName the filter name.
*/
void setFilterName(String filterName);
/**
* Set status.
*
* @param status the status.
*/
void setStatus(int status);
/**
* {@return the web application}
*/
WebApplication getWebApplication();
/**
* Set the web application.
*
* @param webApplication the web application.
*/
void setWebApplication(WebApplication webApplication);
/**
* Is async supported.
*
* @return true if it is, false otherwise.
*/
boolean isAsyncSupported();
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/FilterMapping.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.DispatcherType;
import static jakarta.servlet.DispatcherType.REQUEST;
/**
* The FilterMapping API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface FilterMapping {
/**
* {@return the filter name}
*/
String getFilterName();
/**
* {@return the URL pattern}
*/
String getUrlPattern();
/**
* {@return the dispatcher type}
*
* The dispatcher type is the kind of dispatch that the filter
* mapping applies to. Default is REQUEST, which represents
* the request from the user to the system.
*
*/
default DispatcherType getDispatcherType() {
return REQUEST;
}
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/FilterPriority.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
/**
* The Filter Priority API allows filters that implement this interface to be given priority
* depending on their priority value.
*
*
* Filters with a lower priority are called before filters with a higher priority. Filters
* with an explicit priority are called before filters with no priority at all.
*
* @author Arjan Tijms
*
*/
public interface FilterPriority {
/**
* Returns the priority of this filter in the filter chain.
*
* @return the priority value
*/
int getPriority();
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/HandlesTypesManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import java.util.Set;
/**
* The manager that delivers support for the HandlesTypes annotation.
*
*
* Whenever the onStartup method of a ServletContainerInitializer is called it
* gets passed a set of classes that it expressed interest in. This manager
* delivers the way a web application can vend that set of classes. See the
* JavaDoc of the ServletContainerInitializer for more information about the
* onStartup method.
*
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface HandlesTypesManager {
/**
* Add the annotated class.
*
* @param annotationClass the annotation class.
* @param annotatedClass the annotated class.
*/
void addAnnotatedClass(Class> annotationClass, Class> annotatedClass);
/**
* Add the extending class.
*
* @param baseClass the based class.
* @param extendingClass the extending class.
*/
void addExtendingClass(Class> baseClass, Class> extendingClass);
/**
* Add the implementing class.
*
* @param interfaceClass the interface.
* @param implementingClass the implementing class.
*/
void addImplementingClass(Class> interfaceClass, Class> implementingClass);
/**
* Get the annotated classes.
*
* @param annotationClass the annotation classes.
* @return the annotated classes.
*/
Set> getAnnotatedClasses(Class> annotationClass);
/**
* Get the extending classes.
*
* @param baseClass the base class.
* @return the set of extending classes.
*/
Set> getExtendingClasses(Class> baseClass);
/**
* Get the implementing classes.
*
* @param interfaceClass the interface class.
* @return the set of implementing classes.
*/
Set> getImplementingClasses(Class> interfaceClass);
/**
* Get the set of classes that either are annotated with the given classes,
* implement any of the given classes, or extend any of the given classes.
*
* @param classes the set of given classes.
* @return the set of classes or null if none found.
*/
Set> getClasses(Set> classes);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/HttpHeader.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import java.util.Enumeration;
/**
* The HttpHeader API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface HttpHeader {
/**
* Add the value.
*
* @param value the value to add.
*/
void addValue(String value);
/**
* {@return the name}
*/
String getName();
/**
* {@return the value}
*/
String getValue();
/**
* {@return the values}
*/
Enumeration getValues();
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/HttpHeaderManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import java.util.Enumeration;
/**
* The HttpHeaderManager API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface HttpHeaderManager {
/**
* Add the header.
*
* @param name the name.
* @param value the value.
*/
void addHeader(String name, String value);
/**
* Contains the given header.
*
* @param name the header name.
* @return true if there, false otherwise.
*/
boolean containsHeader(String name);
/**
* {@return the date header}
* @param name the header name.
* @throws IllegalArgumentException when the header could not be converted
* to a date.
*/
long getDateHeader(String name) throws IllegalArgumentException;
/**
* Get the header.
*
* @param name the header name.
* @return the header value.
*/
String getHeader(String name);
/**
* {@return the header names}
*/
Enumeration getHeaderNames();
/**
* Get the headers.
*
* @param name the header name.
* @return the header values.
*/
Enumeration getHeaders(String name);
/**
* Get the int header.
*
* @param name the header name.
* @return the int value.
* @throws NumberFormatException when the value could not be converted to an
* int.
*/
int getIntHeader(String name) throws NumberFormatException;
/**
* Remove the given header.
*
* @param name the header name.
*/
void removeHeader(String name);
/**
* Set the header.
*
* @param name the name.
* @param value the value (string).
*/
void setHeader(String name, String value);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/HttpSessionManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import java.util.EventListener;
import java.util.Set;
import jakarta.servlet.SessionCookieConfig;
import jakarta.servlet.SessionTrackingMode;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
/**
* The HttpSessionManager API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface HttpSessionManager {
/**
* Add a listener.
*
* @param the type.
* @param listener the listener.
*/
void addListener(T listener);
/**
* Attribute added.
*
* @param session the HTTP session.
* @param name the name.
* @param value the value.
*/
void attributeAdded(HttpSession session, String name, Object value);
/**
* Attribute removed.
*
* @param session the HTTP session.
* @param name the name.
* @param value the value.
*/
void attributeRemoved(HttpSession session, String name, Object value);
/**
* Attribute replaced.
*
* @param session the HTTP session.
* @param name the name.
* @param oldValue the old value.
* @param newValue the new value.
*/
void attributeReplaced(HttpSession session, String name, Object oldValue, Object newValue);
/**
* Change the session id and return it.
*
* @param request the request.
* @return the session id.
*/
String changeSessionId(HttpServletRequest request);
/**
* Create a session.
*
* @param request the request.
* @return the session.
*/
HttpSession createSession(HttpServletRequest request);
/**
* Destroys a session.
*
* @param session the HTTP session.
*/
void destroySession(HttpSession session);
/**
* Encode the redirect URL.
*
* @param response the HTTP servlet response.
* @param url the URL.
* @return the encode URL.
*/
String encodeRedirectURL(HttpServletResponse response, String url);
/**
* Encode the URL.
*
* @param response the HTTP servlet response.
* @param url the URL.
* @return the encoded URL.
*/
String encodeURL(HttpServletResponse response, String url);
/**
* {@return the default session tracking modes}
*/
Set getDefaultSessionTrackingModes();
/**
* {@return the effective session tracking modes}
*/
Set getEffectiveSessionTrackingModes();
/**
* {@return the session}
* @param request the request.
* @param currentSessionId the current session id.
*/
HttpSession getSession(HttpServletRequest request, String currentSessionId);
/**
* {@return the session cookie config}
*/
SessionCookieConfig getSessionCookieConfig();
/**
* Get the session timeout (in minutes).
*
* @return the session timeout.
*/
int getSessionTimeout();
/**
* Is the session manager handling this session?
*
* @param sessionId the session id.
* @return true if there is a session with the given session id.
*/
boolean hasSession(String sessionId);
/**
* Set the session timeout (in minutes).
*
* @param timeout the timeout.
*/
void setSessionTimeout(int timeout);
/**
* Set the session tracking modes.
*
* @param sessionTrackingModes the session tracking modes.
*/
void setSessionTrackingModes(Set sessionTrackingModes);
/**
* Set the web application.
*
* @param webApplication the web application.
*/
void setWebApplication(WebApplication webApplication);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/JspManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.ServletRegistration;
import jakarta.servlet.descriptor.JspConfigDescriptor;
/**
* The JspManager API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface JspManager {
/**
* Add the JSP file.
*
* @param webApplication the web application.
* @param servletName the servlet name.
* @param jspFile the jsp file.
* @return the servlet registration.
*/
ServletRegistration.Dynamic addJspFile(WebApplication webApplication, String servletName, String jspFile);
/**
* {@return the JSP config descriptor}
*/
JspConfigDescriptor getJspConfigDescriptor();
/**
* Set the JspConfigDescriptor.
*
* @param jspConfigDescriptor the JspConfigDescriptor.
*/
void setJspConfigDescriptor(JspConfigDescriptor jspConfigDescriptor);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/LocaleEncodingManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
/**
* The LocaleEncodingManager API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface LocaleEncodingManager {
/**
* Add a mapping between a locale and an encoding.
*
* @param locale the locale.
* @param encoding the encoding.
*/
void addCharacterEncoding(String locale, String encoding);
/**
* Get the encoding for the locale.
*
* @param locale the locale.
* @return the encoding, otherwise null.
*/
String getCharacterEncoding(String locale);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/ModuleLayerProcessor.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
/**
* The module layer processor
* @author Thiago Henrique Hupner
*/
public interface ModuleLayerProcessor {
/**
* Process the module layer according to the properties
* @param controller the controller
*/
void processModuleLayerOptions(ModuleLayer.Controller controller);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/MultiPartManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Part;
import java.util.Collection;
/**
* The multi-part manager API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface MultiPartManager {
/**
* Get the parts.
*
* @param webApplication the web application.
* @param request the web application request.
* @return the parts.
* @throws ServletException when the request is not a multipart/form-data request.
*/
Collection getParts(WebApplication webApplication, WebApplicationRequest request) throws ServletException;
/**
* Get the part.
*
* @param webApplication the web application.
* @param request the web application request.
* @param name the name of the part.
* @return the part, or null if not found.
* @throws ServletException when the request is not a multipart/form-data request.
*/
Part getPart(WebApplication webApplication, WebApplicationRequest request, String name) throws ServletException;
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/ObjectInstanceManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.Filter;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import java.util.EventListener;
/**
* The object instance manager API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface ObjectInstanceManager {
/**
* Create the filter.
*
* @param the type.
* @param filterClass the Filter class.
* @return the Filter.
* @throws ServletException when a Servlet error occurs.
*/
T createFilter(Class filterClass) throws ServletException;
/**
* Create the listener.
*
* @param the type.
* @param clazz the class.
* @return the Listener.
* @throws ServletException when a Servlet error occurs.
*/
T createListener(Class clazz) throws ServletException;
/**
* Create the servlet.
*
* @param the type.
* @param clazz the Servlet class.
* @return the Servlet.
* @throws ServletException when a Servlet error occurs.
*/
T createServlet(Class clazz) throws ServletException;
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/Piranha.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
/**
* The Piranha API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface Piranha {
/**
* Get the configuration.
*
* @return the configuration.
*/
PiranhaConfiguration getConfiguration();
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/PiranhaBuilder.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
/**
* The PiranhaBuilder API.
*
* @author Manfred Riem (mriem@manorrock.com)
* @param the concrete Piranha type.
*/
public interface PiranhaBuilder {
/**
* Build the Piranha instance.
*
* @return the Piranha instance.
*/
public T build();
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/PiranhaConfiguration.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import java.io.File;
/**
* Piranha configuration.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface PiranhaConfiguration {
/**
* Get the value as a boolean.
*
* @param key the key.
* @param defaultValue the default value if the key is not found.
* @return the value.
*/
boolean getBoolean(String key, boolean defaultValue);
/**
* Get the value as a class.
*
* @param key the key.
* @return the value.
*/
Class> getClass(String key);
/**
* Get the value as a File.
*
* @param key the key.
* @return the value.
*/
File getFile(String key);
/**
* Get the value as an int.
*
* @param key the key.
* @return the value.
*/
Integer getInteger(String key);
/**
* Get the value as a long.
*
* @param key the key.
* @return the value.
*/
Long getLong(String key);
/**
* Get the value as a string.
*
* @param key the key.
* @return the value (or null if not set).
*/
String getString(String key);
/**
* Set the boolean value.
*
* @param key the key.
* @param value the boolean value.
*/
void setBoolean(String key, Boolean value);
/**
* Set the class value.
*
* @param key the key.
* @param value the class value.
*/
void setClass(String key, Class> value);
/**
* Set the File value.
*
* @param key the key.
* @param value the value.
*/
void setFile(String key, File value);
/**
* Set the integer value.
*
* @param key the key.
* @param value the value.
*/
void setInteger(String key, Integer value);
/**
* Set the long value.
*
* @param key the key.
* @param value the value.
*/
void setLong(String key, Long value);
/**
* Set the string value.
*
* @param key the key.
* @param value the value.
*/
void setString(String key, String value);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/SecurityConstraint.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import java.util.ArrayList;
import java.util.List;
/**
* A security constraint.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class SecurityConstraint {
/**
* Stores the role names.
*/
private List roleNames;
/**
* Stores the security web resource collections.
*/
private List securityWebResourceCollections;
/**
* Stores the transport guarantee.
*/
private String transportGuarantee;
/**
* Constructor.
*/
public SecurityConstraint() {
roleNames = new ArrayList<>();
securityWebResourceCollections = new ArrayList<>();
transportGuarantee = "NONE";
}
/**
* Get the role names.
*
* @return the role names.
*/
public List getRoleNames() {
return roleNames;
}
/**
* Get the security web resource collection.
*
* @return the security web resource collection.
*/
public List getSecurityWebResourceCollections() {
return securityWebResourceCollections;
}
/**
* Get the transport guarantee.
*
* @return the transport guarantee.
*/
public String getTransportGuarantee() {
return transportGuarantee;
}
/**
* Set the role names.
*
* @param roleNames the role names.
*/
public void setRoleNames(List roleNames) {
this.roleNames = roleNames;
}
/**
* Set the security web resource collections.
*
* @param securityWebResourceCollections the security web resource collections.
*/
public void setSecurityWebResourceCollections(
List securityWebResourceCollections) {
this.securityWebResourceCollections = securityWebResourceCollections;
}
/**
* Set the transport guarantee.
*
* @param transportGuarantee the transport guarantee.
*/
public void setTransportGuarantee(String transportGuarantee) {
this.transportGuarantee = transportGuarantee;
}
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/SecurityManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* The SecurityManager API.
*
* @author Manfred Riem (mriem@manorrock.com)
* @author Arjan Tijms
*/
public interface SecurityManager {
/**
* The enum that qualifies the source of the authentication.
*/
enum AuthenticateSource {
/**
* The container / runtime calls authenticate before a request
*/
PRE_REQUEST_CONTAINER,
/**
* The user (code) has programmatically called authenticate
*/
MID_REQUEST_USER
}
/**
* Method that bypasses the authentication mechanism installed by the
* authentication manager and directly invokes an identity store.
*/
interface UsernamePasswordLoginHandler {
/**
* Login.
*
* @param request the request.
* @param username the username.
* @param password the password.
* @return the authenticated identity.
*/
AuthenticatedIdentity login(HttpServletRequest request, String username, String password);
}
/**
* Authenticate the request.
*
* @param request the request.
* @param response the response.
* @return true if authenticated.
* @throws IOException when an I/O error occurs.
* @throws ServletException when a servlet error occurs.
*/
boolean authenticate(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
/**
* Authenticate the request.
*
* @param request the request.
* @param response the response.
* @param source the source or moment from where this authenticate method is
* called
* @return true if authenticated.
* @throws IOException when an I/O error occurs.
* @throws ServletException when a servlet error occurs.
*/
default boolean authenticate(HttpServletRequest request, HttpServletResponse response, AuthenticateSource source) throws IOException, ServletException {
// By default, source and mandatory directive are ignored, and semantics for the 2 parameter
// version hold.
// The 2 parameter version is expected to be essentially source = MID_REQUEST_USER
return authenticate(request, response);
}
/**
* Declare roles.
*
* @param roles the roles.
*/
void declareRoles(String[] roles);
/**
* Declare roles.
*
* @param roles the roles.
*/
default void declareRoles(Collection roles) {
if (roles != null) {
declareRoles(roles.toArray(String[]::new));
}
}
/**
* Get the auth method.
*
* @return the auth method.
*/
default String getAuthMethod() {
return null;
}
/**
* Gets the request object the security system wants to put in place.
*
*
* This method allows the security system (or authentication module being
* delegated to) a custom or, more likely, wrapped request.
*
* @param request the request.
* @param response the response.
* @return a request object that the runtime should put into service
*/
default HttpServletRequest getAuthenticatedRequest(HttpServletRequest request, HttpServletResponse response) {
return request;
}
/**
* Gets the response object the security system wants to put in place.
*
*
* This method allows the security system (or authentication module being
* delegated to) a custom or, more likely, wrapped response.
*
* @param request the request.
* @param response the response.
* @return a response object that the runtime should put into service
*/
default HttpServletResponse getAuthenticatedResponse(HttpServletRequest request, HttpServletResponse response) {
return response;
}
/**
* Get if we are denying uncovered HTTP methods.
*
* @return true if we are, false otherwise.
*/
default boolean getDenyUncoveredHttpMethods() {
return false;
}
/**
* Get the form error page.
*
* @return the form error page.
*/
default String getFormErrorPage() {
return null;
}
/**
* Get the form login page.
*
* @return the form login page.
*/
default String getFormLoginPage() {
return null;
}
/**
* Get the realm name.
*
* @return the realm name.
*/
default String getRealmName() {
return null;
}
/**
* Get the declared roles
*
* @return the roles
*/
Set getRoles();
/**
* Get the security constraints.
*
* @return the security constraints.
*/
List getSecurityConstraints();
/**
* Get the security role references.
*
* @return the security role references.
*/
Map> getSecurityRoleReferences();
/**
* Get the handler that may be used by the login method to contact an
* identity store.
*
* @return the UsernamePasswordLoginHandler or null if not set.
*/
default UsernamePasswordLoginHandler getUsernamePasswordLoginHandler() {
return null;
}
/**
* Get the web application.
*
* @return the web application.
*/
WebApplication getWebApplication();
/**
* Check if the current caller (which can be the anonymous caller) is
* authorized to access the requested resource.
*
*
* If the unauthenticated caller is authorized, then this means the resource
* is public (aka unconstrained, aka unchecked), and the outcome of this
* method MUST be consistent with
* {@link #isRequestedResourcePublic(HttpServletRequest)}.
*
*
* @param request the request.
* @return true if the current caller is allowed to access the requested
* resource, false otherwise
*/
default boolean isCallerAuthorizedForResource(HttpServletRequest request) {
return true;
}
/**
* Check if the current request adheres to the user data constraint, if any.
*
*
* In practice this means checking if HTTPS is used when so required by the
* application.
*
* @param request the request.
* @param response the response.
* @return true if request adheres to constraints, false otherwise
* @throws IOException when an I/O error occurs.
* @throws ServletException when a servlet error occurs.
*/
default boolean isRequestSecurityAsRequired(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
return true;
}
/**
* Check if the requested resource, represented by the request, is public or
* not.
*
* @param request the request.
* @return true if the requested resource can be accessed by public
* (unauthenticated) callers, otherwise false
*/
default boolean isRequestedResourcePublic(HttpServletRequest request) {
return true;
}
/**
* Is the user in the specific role.
*
* @param request the request.
* @param role the role.
* @return true if in the role, false otherwise.
*/
boolean isUserInRole(HttpServletRequest request, String role);
/**
* Login.
*
* @param request the request.
* @param username the username.
* @param password the password.
* @throws ServletException when unable to login.
*/
void login(HttpServletRequest request, String username, String password) throws ServletException;
/**
* Logout.
*
* @param request the request.
* @param response the response.
* @throws ServletException when a servlet error occurs.
*/
void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException;
/**
* Gives the security system the opportunity to process the response after
* the request (after the target resource has been invoked).
*
*
* Although this may be rare to used in practice, it allows for encryption
* of the response, inserting security tokens, signing the response, etc.
*
* @param request the request.
* @param response the response.
* @throws IOException when an I/O error occurs.
* @throws ServletException when a servlet error occurs.
*/
default void postRequestProcess(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
}
/**
* Set the auth method.
*
* @param authMethod the auth method.
*/
default void setAuthMethod(String authMethod) {
}
/**
* Set if we are denying uncovered HTTP methods.
*
* @param denyUncoveredHttpMethods the boolean value.
*/
default void setDenyUncoveredHttpMethods(boolean denyUncoveredHttpMethods) {
}
/**
* Set the form error page.
*
* @param formErrorPage the form error page.
*/
default void setFormErrorPage(String formErrorPage) {
}
/**
* Set the form login page.
*
* @param formLoginPage the form login page.
*/
default void setFormLoginPage(String formLoginPage) {
}
/**
* Set the realm name.
*
* @param realmName the realm name.
*/
default void setRealmName(String realmName) {
}
/**
* Set the security constraints.
*
* @param securityConstraints the security constraints.
*/
void setSecurityConstraints(List securityConstraints);
/**
* Set the security role references.
*
* @param securityRoleReferences the security role references.
*/
void setSecurityRoleReferences(Map> securityRoleReferences);
/**
* Set the handler that may be used by the login method to contact an
* identity store.
*
* @param usernamePasswordLoginHandler the handler
*/
default void setUsernamePasswordLoginHandler(UsernamePasswordLoginHandler usernamePasswordLoginHandler) {
// do nothing, optional method
}
/**
* Set the web application.
*
* @param webApplication the web application.
*/
void setWebApplication(WebApplication webApplication);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/SecurityRoleReference.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
/**
* A security role ref(erence).
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class SecurityRoleReference {
/**
* Stores the role link.
*/
private String roleLink;
/**
* Stores the role name.
*/
private String roleName;
/**
* Constructor.
*/
public SecurityRoleReference() {
}
/**
* Get the role link.
*
* @return the role link.
*/
public String getRoleLink() {
return roleLink;
}
/**
* Get the role name.
*
* @return the role name.
*/
public String getRoleName() {
return roleName;
}
/**
* Set the role link.
*
* @param roleLink the role link.
*/
public void setRoleLink(String roleLink) {
this.roleLink = roleLink;
}
/**
* Set the role name.
*
* @param roleName the role name.
*/
public void setRoleName(String roleName) {
this.roleName = roleName;
}
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/SecurityWebResourceCollection.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import java.util.ArrayList;
import java.util.List;
/**
* A security web resource collection.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class SecurityWebResourceCollection {
/**
* Stores the HTTP methods.
*/
private List httpMethods;
/**
* Stores the HTTP method omissions.
*/
private List httpMethodOmissions;
/**
* Stores the URL patterns.
*/
private List urlPatterns;
/**
* Constructor.
*/
public SecurityWebResourceCollection() {
this.httpMethods = new ArrayList<>();
this.httpMethodOmissions = new ArrayList<>();
this.urlPatterns = new ArrayList<>();
}
/**
* Get the HTTP methods.
*
* @return the HTTP methods.
*/
public List getHttpMethods() {
return httpMethods;
}
/**
* Get the HTTP method omissions.
*
* @return the HTTP method omissions.
*/
public List getHttpMethodOmissions() {
return httpMethodOmissions;
}
/**
* Get the URL patterns.
*
* @return the URL patterns.
*/
public List getUrlPatterns() {
return urlPatterns;
}
/**
* Set the HTTP methods.
*
* @param httpMethods the HTTP methods.
*/
public void setHttpMethods(List httpMethods) {
this.httpMethods = httpMethods;
}
/**
* Set the HTTP method omissions.
*
* @param httpMethodOmissions the HTTP method omissions.
*/
public void setHttpMethodOmissions(List httpMethodOmissions) {
this.httpMethodOmissions = httpMethodOmissions;
}
/**
* Set the URL patterns.
*
* @param urlPatterns the URL patterns.
*/
public void setUrlPatterns(List urlPatterns) {
this.urlPatterns = urlPatterns;
}
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/ServletEnvironment.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.MultipartConfigElement;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletRegistration.Dynamic;
/**
* The environment for a Servlet.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface ServletEnvironment extends Dynamic, ServletConfig {
/**
* Defines the UNAVAILABLE constant.
*/
int UNAVAILABLE = -1;
/**
* {@return the load on startup}
*/
int getLoadOnStartup();
/**
* {@return the multi-part config}
*/
MultipartConfigElement getMultipartConfig();
/**
* {@return the servlet}
*/
Servlet getServlet();
/**
* {@return the servlet class}
*/
Class extends Servlet> getServletClass();
/**
* {@return the status}
*/
int getStatus();
/**
* {@return the web application}
*/
WebApplication getWebApplication();
/**
* Is async supported.
*
* @return true if it is, false otherwise.
*/
boolean isAsyncSupported();
/**
* Set the class name.
*
* @param className the class name.
*/
void setClassName(String className);
/**
* Set the servlet.
*
* @param servlet the servlet.
*/
void setServlet(Servlet servlet);
/**
* Set the status.
*
* @param status the status.
*/
void setStatus(int status);
/**
* The exception that caused this servlet to become unavailable
*
* @return the exception.
*/
Throwable getUnavailableException();
/**
* Sets the exception that caused this servlet to become unavailable
*
* @param unavailableException the unavailable exception.
*/
void setUnavailableException(Throwable unavailableException);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/ServletInvocation.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import static cloud.piranha.core.api.ServletEnvironment.UNAVAILABLE;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletConfig;
import java.util.List;
/**
* The ServletInvocation API.
*
*
* This type holds data necessary to invoke a Servlet.
*
*
* @author Arjan Tijms
*
*/
public interface ServletInvocation {
/**
* The original path used to base the Servlet invocation on.
*
* @return the full invocation path
*/
String getInvocationPath();
/**
* {@return the servlet name}
*/
String getServletName();
/**
* {@return the servlet path}
*/
String getServletPath();
/**
* Gets the original servlet path.
*
*
* The original servlet path differs from the servlet path if the
* invocation locator has found an alternative resource than the one
* requested. This is typically the case for welcome pages.
*
* @return the original servlet path.
*/
default String getOriginalServletPath() {
return getServletPath();
}
/**
* {@return the path info}
*/
String getPathInfo();
/**
* {@return the web application request mapping}
*/
WebApplicationRequestMapping getApplicationRequestMapping();
/**
* {@return the servlet environment}
*/
ServletEnvironment getServletEnvironment();
/**
* {@return the filter environments}
*/
List getFilterEnvironments();
/**
* {@return the filter chain}
*/
FilterChain getFilterChain();
/**
* {@return whether this invocation is obtained from a getNamedDispatcher}
*/
default boolean isFromNamed() {
return false;
}
/**
* Set the from named flag.
*
* @param fromNamed whether this invocation is obtained from a getNamedDispatcher
*/
default void setFromNamed(boolean fromNamed) {
// Ignore
}
/**
* Do we have a servlet.
*
* @return true if we do, false otherwise.
*/
default boolean hasServlet() {
return getServletEnvironment() != null && getServletEnvironment().getServlet() != null;
}
/**
* Do we have a filter.
*
* @return true if we do, false otherwise.
*/
default boolean hasFilter() {
return getFilterEnvironments() != null;
}
/**
* Is the servlet unavailable.
*
* @return true if it is, false otherwise.
*/
default boolean isServletUnavailable() {
return getServletEnvironment() != null && getServletEnvironment().getStatus() == UNAVAILABLE;
}
/**
* Can we invoke.
*
* @return true if we can, false otherwise.
*/
default boolean canInvoke() {
return hasServlet() || hasFilter();
}
/**
* {@return the servlet configuration}
*/
default ServletConfig getServletConfig() {
if (!hasServlet()) {
return null;
}
return getServletEnvironment().getServlet().getServletConfig();
}
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/ServletRequestManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.ServletRequest;
import java.util.EventListener;
import jakarta.servlet.http.HttpServletRequest;
/**
* The ServletRequest manager.
*
* @author Arjan Tijms
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface ServletRequestManager {
/**
* Add a listener.
*
* @param the type.
* @param listener the listener.
*/
void addListener(T listener);
/**
* Fire the attribute added event.
*
* @param request the request.
* @param name the name.
* @param value the value.
*/
void attributeAdded(HttpServletRequest request, String name, Object value);
/**
* Fire the attribute removed event.
*
* @param request the request.
* @param name the name.
* @param value the value
*/
void attributeRemoved(HttpServletRequest request, String name, Object value);
/**
* Fire the attribute replaced event.
*
* @param request the request.
* @param name the name.
* @param value the value.
*/
void attributeReplaced(HttpServletRequest request, String name, Object value);
/**
* Fire the request destroyed event.
*
* @param request the request.
*/
void requestDestroyed(ServletRequest request);
/**
* Fire the request initialized event.
*
* @param request the request.
*/
void requestInitialized(ServletRequest request);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplication.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import cloud.piranha.resource.api.Resource;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.FilterRegistration;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletContainerInitializer;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRegistration;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.descriptor.JspConfigDescriptor;
import java.io.IOException;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
/**
* The WebApplication API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WebApplication extends ServletContext {
/**
* Status enum.
*/
enum Status {
/**
* Web application is in setup mode.
*/
SETUP,
/**
* Web application has processed system declared constructs (e.g.
* web.xml / web-fragment.xml and Servlet annotations).
*/
DECLARED,
/**
* Web application is initialized.
*/
INITIALIZED,
/**
* Web application is servicing.
*/
SERVICING,
/**
* Web application is in error state.
*/
ERROR
}
/**
* Add a mapping for the given filter.
*
* @param filterName the filter name.
* @param urlPatterns the URL patterns.
* @return the possible empty set of already mapped URL patterns.
* @see FilterRegistration#addMappingForUrlPatterns(EnumSet, boolean,
* String...)
*/
default Set addFilterMapping(String filterName, String... urlPatterns) {
return addFilterMapping(filterName, true, urlPatterns);
}
/**
* Add a mapping for the given filter.
*
* @param filterName the filter name.
* @param isMatchAfter true to call the filter this mapping applies to after
* declared ones, false to call it before declared ones.
* @param urlPatterns the URL patterns.
* @return the possible empty set of already mapped URL patterns.
* @see FilterRegistration#addMappingForUrlPatterns(EnumSet, boolean,
* String...)
*/
default Set addFilterMapping(String filterName, boolean isMatchAfter, String... urlPatterns) {
return addFilterMapping(null, filterName, isMatchAfter, urlPatterns);
}
/**
* Add a mapping for the given filter.
*
* @param dispatcherTypes the dispatcher types. Can be null to use default
* DispatcherType.REQUEST.
* @param filterName the filter name.
* @param isMatchAfter true to call the filter this mapping applies to after
* declared ones, false to call it before declared ones.
* @param urlPatterns the URL patterns.
* @return the possible empty set of already mapped URL patterns.
* @see FilterRegistration#addMappingForUrlPatterns(EnumSet, boolean,
* String...)
*/
Set addFilterMapping(Set dispatcherTypes, String filterName, boolean isMatchAfter, String... urlPatterns);
/**
* Add a servlet container initializer.
*
* @param className the class name.
*/
void addInitializer(String className);
/**
* Add a servlet container initializer.
*
* @param servletContainerInitializer the servletContainerInitializer
* instance
*/
void addInitializer(ServletContainerInitializer servletContainerInitializer);
/**
* Add the mime type.
*
* @param extension the extension (without the dot).
* @param mimeType the mime type to return.
*/
void addMimeType(String extension, String mimeType);
/**
* Add the resource.
*
* @param resource the resouce.
*/
void addResource(Resource resource);
/**
* Add a mapping for the given servlet.
*
* @param servletName the servlet name.
* @param urlPatterns the URL patterns.
* @return the possible empty set of already mapped URL patterns.
* @see ServletRegistration#addMapping(String...)
*/
Set addServletMapping(String servletName, String... urlPatterns);
/**
* Destroy the web application.
*
* @return the web application.
*/
WebApplication destroy();
/**
* Get the default servlet.
*
* @return the default Servlet.
*/
Servlet getDefaultServlet();
/**
* Gets the ServletContainerInitializers
*
* @return list of ServletContainerInitializers
*/
List getInitializers();
/**
* Get the web application manager.
*
* @return the web application manager.
*/
WebApplicationManager getManager();
/**
* Get the mappings for a particular servlet.
*
* @param servletName the servlet name.
* @return the possible empty set of mapped URL patterns.
* @see ServletRegistration#getMappings()
*/
Collection getMappings(String servletName);
/**
* Get the request.
*
* @param response the response.
* @return the request.
*/
ServletRequest getRequest(ServletResponse response);
/**
* Get the response.
*
* @param request the request.
* @return the response.
*/
ServletResponse getResponse(ServletRequest request);
/**
* Returns the unique Id of this web application corresponding to this
* ServletContext.
*
* @return the servlet context id.
*/
default String getServletContextId() {
return getVirtualServerName() + " " + getContextPath();
}
/**
* Get the status.
*
* @return the status.
*/
Status getStatus();
/**
* Initialize the web application.
*
* @return the web application.
*/
WebApplication initialize();
/**
* Is the application distributable.
*
* @return true if it is, false otherwise.
*/
boolean isDistributable();
/**
* Is the web application initialized.
*
* @return true if it is, false otherwise.
*/
boolean isInitialized();
/**
* Is the web application metadata complete.
*
* @return true if it is, false otherwise.
*/
boolean isMetadataComplete();
/**
* Is the web application currently servicing requests.
*
* @return true if it is, false otherwise.
*/
boolean isServicing();
/**
* Link the request and response.
*
* @param request the request.
* @param response the response.
*/
void linkRequestAndResponse(ServletRequest request, ServletResponse response);
/**
* Remove a mapping for a servlet.
*
* @param urlPattern the URL pattern
* @return the Servlet name the pattern was mapped to, or null if no prior
* mapping.
*/
String removeServletMapping(String urlPattern);
/**
* Service the request.
*
* @param request the request.
* @param response the response.
* @throws ServletException when a servlet error occurs.
* @throws IOException when an I/O error occurs.
*/
void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException;
/**
* Set the class loader.
*
* @param classLoader the class loader.
*/
void setClassLoader(ClassLoader classLoader);
/**
* Set the context path.
*
* @param contextPath the context path.
*/
void setContextPath(String contextPath);
/**
* Set the default servlet.
*
* @param defaultServlet the default servlet.
*/
void setDefaultServlet(Servlet defaultServlet);
/**
* Set if the web application is distributable.
*
* @param distributable the distributable flag.
*/
void setDistributable(boolean distributable);
/**
* Set the effective major version.
*
* @param version the effective major version.
*/
void setEffectiveMajorVersion(int version);
/**
* Set the effective minor version.
*
* @param version the effective minor version.
*/
void setEffectiveMinorVersion(int version);
/**
* Set the JSP config descriptor.
*
* @param descriptor the descriptor.
*/
void setJspConfigDescriptor(JspConfigDescriptor descriptor);
/**
* Set the metadata complete flag.
*
* @param metadataComplete the metadata complete flag.
*/
void setMetadataComplete(boolean metadataComplete);
/**
* Set the servlet context name.
*
* @param servletContextName the servlet context name.
*/
void setServletContextName(String servletContextName);
/**
* Set the status.
*
* @param status the status.
*/
void setStatus(Status status);
/**
* Set the virtual server name.
*
* @param virtualServerName the virtual server name.
*/
void setVirtualServerName(String virtualServerName);
/**
* Set the web application request mapper.
*
* @param webApplicationRequestMapper the web application request mapper.
*/
void setWebApplicationRequestMapper(WebApplicationRequestMapper webApplicationRequestMapper);
/**
* Start servicing.
*
* @return the web application.
*/
WebApplication start();
/**
* Stop servicing.
*
* @return the web application.
*/
WebApplication stop();
/**
* Unlink the request and response.
*
* @param request the request.
* @param response the response.
*/
void unlinkRequestAndResponse(ServletRequest request, ServletResponse response);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationClassLoader.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import cloud.piranha.resource.api.ResourceManagerClassLoader;
/**
* The WebApplicationClassLoader API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WebApplicationClassLoader extends ResourceManagerClassLoader {
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationExtension.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
/**
* The web application extension API.
*
*
* A web application extension can be used to automatically configure the web
* application according to what the extension delivers, or you can use it as a
* way to compose extensions together in one extension.
*
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WebApplicationExtension {
/**
* Configure the web application.
*
* @param webApplication the web application to configure.
*/
default void configure(WebApplication webApplication) {
}
/**
* Extend the web application.
*
* @param context the context.
*/
default void extend(WebApplicationExtensionContext context) {
}
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationExtensionContext.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
/**
* The web application extension context API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WebApplicationExtensionContext {
/**
* Add the extension to the web application.
*
*
* This will add this extension to the list of extensions that will be used
* when configuring the web application.
*
*
* @param extension the extension.
*/
void add(Class extends WebApplicationExtension> extension);
/**
* Add the extension to the web application.
*
*
* This will add this extension to the list of extensions that will be used
* when configuring the web application.
*
*
* @param extension the extension.
*/
void add(WebApplicationExtension extension);
/**
* Remove the extension from the web application.
*
*
* This will remove the extension from the list of extensions that will be
* used when configuring the web application.
*
*
* NOTE this will ONLY remove this extension. Any extensions that were added
* to the list by this extension BEFORE it was removed will NOT be removed
* from the list of extensions. This is by design.
*
*
* @param extension the extension.
*/
void remove(Class extends WebApplicationExtension> extension);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationInputStream.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* The web application input stream.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public abstract class WebApplicationInputStream extends ServletInputStream implements Runnable {
/**
* Stores the finished flag.
*/
protected boolean finished;
/**
* Stores the read index.
*/
protected int index;
/**
* Stores the input stream.
*/
protected InputStream inputStream;
/**
* Stores the read listener.
*/
protected ReadListener readListener;
/**
* Stores the read listener lock.
*/
protected Lock readListenerLock = new ReentrantLock();
/**
* Stores the web application request.
*/
protected WebApplicationRequest webApplicationRequest;
/**
* Constructor.
*/
public WebApplicationInputStream() {
inputStream = new ByteArrayInputStream(new byte[0]);
}
@Override
public void close() throws IOException {
super.close();
finished = true;
}
/**
* Get the read listener.
*
* @return the read listener, or null if not set.
*/
public ReadListener getReadListener() {
return readListener;
}
@Override
public boolean isFinished() {
return finished;
}
@Override
public boolean isReady() {
boolean ready;
try {
readListenerLock.lock();
ready = inputStream.available() > 0;
} catch (IOException ioe) {
ready = false;
} finally {
readListenerLock.unlock();
}
return ready;
}
@Override
public int read() throws IOException {
int read;
if (readListener == null) {
if (finished || webApplicationRequest.getContentLength() == 0) {
return -1;
}
read = readWithTimeout();
index++;
if (index == webApplicationRequest.getContentLength() || read == -1) {
finished = true;
}
} else {
read = readWithTimeout();
}
return read;
}
/**
* Read with a timeout.
*
* @return the byte read or -1 if the end has been reached (or a timeout
* occurred).
*/
private int readWithTimeout() {
int read = -1;
/*
* Because we do not know if the underlying inputstream can
* block indefinitely we make sure we read from the inputstream
* with a timeout so we do not block the thread indefinitely.
*
* If we do not get a read to succeed within the 30 seconds
* timeout we return -1 to indicate we assume the end of the
* stream has been reached.
*/
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable readTask = () -> {
return inputStream.read();
};
Future future = executor.submit(readTask);
try {
read = future.get(30, TimeUnit.SECONDS);
} catch (TimeoutException | InterruptedException | ExecutionException e) {
read = -1;
} finally {
executor.shutdown();
}
return read;
}
@Override
public void run() {
while (true) {
try {
if (isReady()) {
try {
readListenerLock.lock();
readListener.onDataAvailable();
} finally {
readListenerLock.unlock();
}
}
if (!finished) {
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
if (finished) {
try {
readListenerLock.lock();
readListener.onAllDataRead();
break;
} finally {
readListenerLock.unlock();
}
}
} catch (IOException ioe) {
readListener.onError(ioe);
break;
}
}
}
/**
* Set the input stream.
*
* @param inputStream the input stream.
*/
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
@Override
public void setReadListener(ReadListener readListener) {
if (readListener == null) {
throw new NullPointerException("Read listener cannot be null");
}
if (this.readListener != null) {
throw new IllegalStateException("Read listener can only be set once");
}
if (!webApplicationRequest.isAsyncStarted() && !webApplicationRequest.isUpgraded()) {
throw new IllegalStateException("Read listener cannot be set as the request is not upgraded nor the async is started");
}
this.readListener = readListener;
Thread thread = new Thread(this);
thread.start();
}
/**
* Set the web application request.
*
* @param webApplicationRequest the web application request.
*/
public void setWebApplicationRequest(WebApplicationRequest webApplicationRequest) {
this.webApplicationRequest = webApplicationRequest;
}
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import cloud.piranha.resource.api.ResourceManager;
/**
* The WebApplicationManager API.
*
*
* This API makes it possible to access the various managers used to deliver
* specific functionality (e.g mime-type handling, welcome-file handling, etc).
*
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WebApplicationManager {
/**
* Get the annotation manager.
*
* @return the annotation manager.
*/
AnnotationManager getAnnotationManager();
/**
* Get the async manager.
*
* @return the async manager.
*/
AsyncManager getAsyncManager();
/**
* Get the error page manager.
*
* @return the error page manager.
*/
ErrorPageManager getErrorPageManager();
/**
* Get the dispatcher manager.
*
* @return the dispatcher manager.
*/
DispatcherManager getDispatcherManager();
/**
* Get the HandlesTypes manager.
*
* @return the HandlesTypes manager.
*/
HandlesTypesManager getHandlesTypesManager();
/**
* Get the HTTP session manager.
*
* @return the HTTP session manager.
*/
HttpSessionManager getHttpSessionManager();
/**
* Get the JSP manager.
*
* @return the JSP manager.
*/
JspManager getJspManager();
/**
* Get the locale encoding manager.
*
* @return the locale encoding manager.
*/
LocaleEncodingManager getLocaleEncodingManager();
/**
* Get the multi-part manager.
*
* @return the multi-part manager.
*/
MultiPartManager getMultiPartManager();
/**
* Get the object instance manager.
*
* @return the object instance manager.
*/
ObjectInstanceManager getObjectInstanceManager();
/**
* Get the resource manager.
*
* @return the resource manager.
*/
ResourceManager getResourceManager();
/**
* Get the security manager.
*
* @return the security manager.
*/
SecurityManager getSecurityManager();
/**
* Get the servlet request manager.
*
* @return the servlet request manager.
*/
ServletRequestManager getServletRequestManager();
/**
* Get the welcome file manager.
*
* @return the welcome file manager.
*/
WelcomeFileManager getWelcomeFileManager();
/**
* Set the annotation manager.
*
* @param annotationManager the annotation manager.
*/
void setAnnotationManager(AnnotationManager annotationManager);
/**
* Set the async manager.
*
* @param asyncManager the async manager.
*/
void setAsyncManager(AsyncManager asyncManager);
/**
* Set the error page manager.
*
* @param errorPageManager the error page manager.
*/
void setErrorPageManager(ErrorPageManager errorPageManager);
/**
* Set the HandlesTypes manager.
*
* @param handlesTypesManager the HandlesTypes manager.
*/
void setHandlesTypesManager(HandlesTypesManager handlesTypesManager);
/**
* Set the HTTP session manager.
*
* @param httpSessionManager the HTTP session manager.
*/
void setHttpSessionManager(HttpSessionManager httpSessionManager);
/**
* Set the JSP manager.
*
* @param jspManager the JSP manager.
*/
void setJspManager(JspManager jspManager);
/**
* Set the locale encoding manager.
*
* @param localeEncodingManager the locale encoding manager.
*/
void setLocaleEncodingManager(LocaleEncodingManager localeEncodingManager);
/**
* Set the multi-part manager.
*
* @param multiPartManager the multi-part manager.
*/
void setMultiPartManager(MultiPartManager multiPartManager);
/**
* Set the object instance manager.
*
* @param objectInstanceManager the object instance manager.
*/
void setObjectInstanceManager(ObjectInstanceManager objectInstanceManager);
/**
* Set the resource manager.
*
* @param resourceManager the resource manager.
*/
void setResourceManager(ResourceManager resourceManager);
/**
* Set the security manager.
*
* @param securityManager the security manager.
*/
void setSecurityManager(SecurityManager securityManager);
/**
* Set the servlet request manager.
*
* @param servletRequestManager the servlet request manager.
*/
void setServletRequestManager(ServletRequestManager servletRequestManager);
/**
* Set the welcome file manager.
*
* @param welcomeFileManager the welcome file manager.
*/
void setWelcomeFileManager(WelcomeFileManager welcomeFileManager);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationOutputStream.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.WriteListener;
import java.io.IOException;
import java.io.OutputStream;
/**
* The WebApplicationOutputStream API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public abstract class WebApplicationOutputStream extends ServletOutputStream {
/**
* Default constructor.
*/
protected WebApplicationOutputStream() {
}
/**
* Flush the buffer.
*
* @throws IOException when an I/O error occurs.
*/
public abstract void flushBuffer() throws IOException;
/**
* Get the buffer size.
*
* @return the buffer size.
*/
public abstract int getBufferSize();
/**
* Get the output stream.
*
* @return the output stream.
*/
public abstract OutputStream getOutputStream();
/**
* Get the web application response.
*
* @return the web application response.
*/
public abstract WebApplicationResponse getResponse();
/**
* Get the write listener.
*
* @return the write listener.
*/
public abstract WriteListener getWriteListener();
/**
* Reset the buffer.
*/
public abstract void resetBuffer();
/**
* Set the buffer size.
*
* @param bufferSize the buffer size.
*/
public abstract void setBufferSize(int bufferSize);
/**
* Set the output stream.
*
* @param outputStream the output stream.
*/
public abstract void setOutputStream(OutputStream outputStream);
/**
* Set the web application response.
*
* @param response the web application response.
*/
public abstract void setResponse(WebApplicationResponse response);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationPrintWriter.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import java.io.PrintWriter;
import java.io.Writer;
/**
* The WebApplicationPrintWriter API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class WebApplicationPrintWriter extends PrintWriter {
/**
* Stores the response object.
*/
protected WebApplicationResponse response;
/**
* Constructor.
*
* @param response the response object.
* @param writer the writer.
* @param autoFlush the auto flush flag.
*/
public WebApplicationPrintWriter(WebApplicationResponse response, Writer writer, boolean autoFlush) {
super(writer, autoFlush);
this.response = response;
}
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationRequest.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.MultipartConfigElement;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpUpgradeHandler;
import java.security.Principal;
import java.util.Map;
/**
* The WebApplicationRequest API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WebApplicationRequest extends HttpServletRequest {
/**
* Get the modifiable parameter map.
*
* @return the modifiable parameter map.
*/
Map getModifiableParameterMap();
/**
* {@return the multipartConfig}
*/
default MultipartConfigElement getMultipartConfig() {
return null;
}
/**
* {@return the upgrade handler}
*/
default HttpUpgradeHandler getUpgradeHandler() {
return null;
}
/**
* Get the web application input stream.
*
* @return the web application input stream.
*/
default WebApplicationInputStream getWebApplicationInputStream() {
return null;
}
/**
* {@return true when upgraded, false otherwise}
*/
default boolean isUpgraded() {
return false;
}
/**
* Set the async supported flag.
*
* @param asyncSupported the async supported flag.
*/
void setAsyncSupported(boolean asyncSupported);
/**
* Set the auth type.
*
* @param authType the auth type.
*/
void setAuthType(String authType);
/**
* Set the context path.
*
* @param contextPath the context path.
*/
void setContextPath(String contextPath);
/**
* Set the dispatcher type.
*
* @param dispatcherType the dispatcher type.
*/
void setDispatcherType(DispatcherType dispatcherType);
/**
* Set the requested session id.
*
* @param requestedSessionId the requested session id.
*/
default void setRequestedSessionId(String requestedSessionId) {
}
/**
* Set the servlet path.
*
* @param servletPath the servlet path.
*/
void setServletPath(String servletPath);
/**
* Set the user principal.
*
* @param userPrincipal the user principal.
*/
void setUserPrincipal(Principal userPrincipal);
/**
* Set the web application.
*
* @param webApplication the web application.
*/
void setWebApplication(WebApplication webApplication);
/**
* Set the path info.
*
* @param pathInfo the path info.
*/
default void setPathInfo(String pathInfo) {
}
/**
* Set the query string.
*
* @param queryString the query string.
*/
default void setQueryString(String queryString) {
}
/**
* Set the web application input stream.
*
* @param webApplicationInputStream the web application input stream.
*/
default void setWebApplicationInputStream(
WebApplicationInputStream webApplicationInputStream) {
}
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationRequestMapper.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.DispatcherType;
import static jakarta.servlet.DispatcherType.REQUEST;
import java.util.Collection;
import java.util.Set;
/**
* The WebApplicationRequestMapper API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WebApplicationRequestMapper {
/**
* Add a servlet mapping.
*
*
* This method will throw an IllegalArgumentException if a URL pattern
* is null or empty (Servlet:JAVADOC:696.3).
*
*
* This method accommodates for a URL pattern that does not start with a
* leading slash to support pre-Servlet 2.3 application to operate
* properly.
*
*
* @param servletName the servlet name.
* @param urlPatterns the URL patterns to map (aka mappings).
* @return the URL patterns that were already added.
*/
Set addServletMapping(String servletName, String... urlPatterns);
/**
* Remove a mapping.
*
* @param urlPattern the URL pattern
* @return the Servlet name the pattern was mapped to, or null if no prior mapping.
*/
String removeServletMapping(String urlPattern);
/**
* Add a filter mapping.
*
*
* This adds the filter mappings at the end of list of existing mappings (if any).
*
* @param filterName the filter name.
* @param urlPatterns the URL patterns to map (aka mappings).
* @return the URL patterns that were added.
*/
default Set addFilterMapping(String filterName, String... urlPatterns) {
return addFilterMapping(null, filterName, urlPatterns);
}
/**
* Add a filter mapping.
*
*
* This adds the filter mappings at the end of list of existing mappings (if any).
*
* @param dispatcherTypes the dispatcher types.
* @param filterName the filter name.
* @param urlPatterns the URL patterns to map (aka mappings).
* @return the URL patterns that were added.
*/
Set addFilterMapping(Set dispatcherTypes, String filterName, String... urlPatterns);
/**
* Add a filter mapping.
*
*
* This adds the filter mappings at the start of list of existing mappings (if any).
* If there are existing mappings these are shifted to the right.
*
* @param filterName the filter name.
* @param urlPatterns the URL patterns to map (aka mappings).
* @return the URL patterns that were added.
*/
default Set addFilterMappingBeforeExisting(String filterName, String... urlPatterns) {
return addFilterMappingBeforeExisting(null, filterName, urlPatterns);
}
/**
* Add a filter mapping.
*
*
* This adds the filter mappings at the start of list of existing mappings (if any).
* If there are existing mappings these are shifted to the right.
*
* @param dispatcherTypes the dispatcher types.
* @param filterName the filter name.
* @param urlPatterns the URL patterns to map (aka mappings).
* @return the URL patterns that were added.
*/
Set addFilterMappingBeforeExisting(Set dispatcherTypes, String filterName, String... urlPatterns);
/**
* Find the filter mappings for the given path.
*
* @param path the path.
* @return the mappings.
*/
default Collection findFilterMappings(String path) {
return findFilterMappings(REQUEST, path);
}
/**
* Find the filter mappings for the given path.
*
* @param dispatcherType the dispatcher type.
* @param path the path.
* @return the mappings.
*/
Collection findFilterMappings(DispatcherType dispatcherType, String path);
/**
* Find the servlet mapping for the given path.
*
* @param path the path.
* @return the mapping, or null if not found.
*/
WebApplicationRequestMapping findServletMapping(String path);
/**
* Get the mappings for the specified servlet.
*
* @param servletName the servlet name.
* @return the servlet mappings, or an empty collection if none.
*/
Collection getServletMappings(String servletName);
/**
* Get the default servlet.
*
* @return the default servlet.
*/
default String getDefaultServlet() {
return null;
}
/**
* Get the servlet name for the specified mapping.
*
* @param mapping the mapping.
* @return the servlet name, or null if not found.
*/
String getServletName(String mapping);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationRequestMapping.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
/**
* The WebApplicationRequestMapping API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WebApplicationRequestMapping {
/**
* {@return the match value}
*/
String getMatchValue();
/**
* {@return the path}
*/
String getPattern();
/**
* Is this an exact match.
*
* @return true it it is, false otherwise.
*/
boolean isExact();
/**
* Is this an extension match.
*
* @return true if it is, false otherwise.
*/
boolean isExtension();
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationResponse.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Collection;
/**
* The WebApplicationResponse API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WebApplicationResponse extends HttpServletResponse {
/**
* Close the async response.
*/
void closeAsyncResponse();
/**
* Get the content language.
*
* @return the content language.
*/
String getContentLanguage();
/**
* Get the content length.
*
* @return the content length.
*/
long getContentLength();
/**
* {@return the cookies}
*/
Collection getCookies();
/**
* {@return the response closer}
*/
Runnable getResponseCloser();
/**
* Get the status message.
*
* @return the status message.
*/
String getStatusMessage();
/**
* Get the web application.
*
* @return the web application.
*/
WebApplication getWebApplication();
/**
* {@return the web application output stream}
*/
WebApplicationOutputStream getWebApplicationOutputStream();
/**
* Are we in body only mode.
*
* @return true if we are only sending the body, false otherwise.
*/
boolean isBodyOnly();
/**
* Is the buffer resetting.
*
* @return true if it is, false otherwise.
*/
boolean isBufferResetting();
/**
* Is the writer acquired.
*
* @return true if it is, false otherwise.
*/
boolean isWriterAcquired();
/**
* Set the committed flag.
*
* @param committed the committed flag.
*/
void setCommitted(boolean committed);
/**
* Set the body only mode.
*
* @param bodyOnly the body only mode.
*/
void setBodyOnly(boolean bodyOnly);
/**
* Set the response closer.
*
* @param responseCloser the response closer.
*/
void setResponseCloser(Runnable responseCloser);
/**
* Set the web application.
*
* @param webApplication the web application.
*/
void setWebApplication(WebApplication webApplication);
/**
* Set the web application output stream.
*
* @param outputStream the web application output stream.
*/
void setWebApplicationOutputStream(WebApplicationOutputStream outputStream);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationServer.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import jakarta.servlet.ServletException;
import java.io.IOException;
/**
* The WebApplicationServer API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WebApplicationServer {
/**
* Add a web application.
*
* @param webApplication the web application to add.
*/
void addWebApplication(WebApplication webApplication);
/**
* {@return the request mapper}
*/
WebApplicationServerRequestMapper getRequestMapper();
/**
* Service the request and response.
*
* @param request the request.
* @param response the response.
* @throws IOException when an I/O error occurs.
* @throws ServletException when a Servlet error occurs.
*/
void service(WebApplicationRequest request, WebApplicationResponse response)
throws IOException, ServletException;
/**
* Initialize the server.
*/
void initialize();
/**
* Set the request mapper.
*
* @param requestMapper the request mapper.
*/
void setRequestMapper(WebApplicationServerRequestMapper requestMapper);
/**
* Start the server.
*/
void start();
/**
* Stop the server.
*/
void stop();
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WebApplicationServerRequestMapper.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import java.util.Set;
/**
* The WebApplicationServerRequestMapper API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WebApplicationServerRequestMapper {
/**
* Add a mapping.
*
* @param webApplication the web application.
* @param urlPatterns the url patterns to map (aka mappings).
* @return the url patterns added.
*/
Set addMapping(WebApplication webApplication, String... urlPatterns);
/**
* Find a mapping for the given path.
*
* @param path the path.
* @return the mapping, or null if not found.
*/
WebApplication findMapping(String path);
}
================================================
FILE: core/api/src/main/java/cloud/piranha/core/api/WelcomeFileManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import java.util.List;
/**
* The WelcomeFileManager API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public interface WelcomeFileManager {
/**
* Add a welcome file.
*
* @param welcomeFile the welcome file.
*/
void addWelcomeFile(String welcomeFile);
/**
* {@return the welcome file list}
*/
List getWelcomeFileList();
}
================================================
FILE: core/api/src/main/java/module-info.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* This module defines the core Piranha APIs.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
module cloud.piranha.core.api {
exports cloud.piranha.core.api;
opens cloud.piranha.core.api;
requires transitive cloud.piranha.resource.api;
requires transitive jakarta.servlet;
}
================================================
FILE: core/api/src/test/java/cloud/piranha/core/api/AttributeManagerTest.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.api;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Hashtable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class AttributeManagerTest {
private AttributeManager attributeManager;
private Hashtable attributes;
@BeforeEach
void setUp() {
attributes = new Hashtable<>();
attributeManager = new AttributeManager() {
@Override
public Object getAttribute(String name) {
return attributes.get(name);
}
@Override
public Enumeration getAttributeNames() {
return attributes.keys();
}
@Override
public void removeAttribute(String name) {
attributes.remove(name);
}
@Override
public void setAttribute(String name, Object value) {
attributes.put(name, value);
}
};
}
@Test
void testGetAttribute() {
attributeManager.setAttribute("test", "value");
assertEquals("value", attributeManager.getAttribute("test"));
}
@Test
void testGetAttributeNames() {
attributeManager.setAttribute("test1", "value1");
attributeManager.setAttribute("test2", "value2");
Enumeration names = attributeManager.getAttributeNames();
assertTrue(Collections.list(names).contains("test1"));
names = attributeManager.getAttributeNames();
assertTrue(Collections.list(names).contains("test2"));
}
@Test
void testRemoveAttribute() {
attributeManager.setAttribute("test", "value");
attributeManager.removeAttribute("test");
assertNull(attributeManager.getAttribute("test"));
}
@Test
void testSetAttribute() {
attributeManager.setAttribute("test", "value");
assertEquals("value", attributeManager.getAttribute("test"));
}
@Test
void testContainsAttribute() {
attributeManager.setAttribute("test", "value");
assertTrue(attributeManager.containsAttribute("test"));
attributeManager.removeAttribute("test");
assertFalse(attributeManager.containsAttribute("test"));
}
}
================================================
FILE: core/impl/pom.xml
================================================
4.0.0
cloud.piranha.core
project
25.4.0-SNAPSHOT
piranha-core-impl
jar
Piranha - Core - Implementation
org.jacoco
jacoco-maven-plugin
check
check
BUNDLE
INSTRUCTION
COVEREDRATIO
0.69
BRANCH
COVEREDRATIO
0.57
cloud.piranha
bom
${project.version}
pom
import
cloud.piranha.core
piranha-core-api
${project.version}
compile
cloud.piranha.resource
piranha-resource-impl
${project.version}
compile
cloud.piranha.http
piranha-http-impl
${project.version}
test
org.junit.jupiter
junit-jupiter-api
test
org.junit.jupiter
junit-jupiter-params
test
org.junit.jupiter
junit-jupiter-engine
test
default
file:///tmp/piranha/core/impl/
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/AsyncHttpDispatchWrapper.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import java.security.Principal;
import java.util.ArrayList;
import static java.util.Collections.enumeration;
import static java.util.Collections.list;
import static java.util.Collections.unmodifiableMap;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import static java.util.Objects.requireNonNull;
import cloud.piranha.core.api.AttributeManager;
import cloud.piranha.core.api.WebApplication;
import cloud.piranha.core.api.WebApplicationRequest;
import jakarta.servlet.AsyncContext;
import jakarta.servlet.DispatcherType;
import static jakarta.servlet.DispatcherType.ASYNC;
import jakarta.servlet.MultipartConfigElement;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
/**
* The async HTTP dispatch wrapper.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class AsyncHttpDispatchWrapper extends HttpServletRequestWrapper implements WebApplicationRequest {
/**
* Stores the servlet path.
*/
private String servletPath;
/**
* Stores the path info.
*/
private String pathInfo;
/**
* Stores the request URI.
*/
private String requestURI;
/**
* Stores the query string.
*/
private String queryString;
/**
* Stores the async context.
*/
private AsyncContext asyncContext;
/**
* Stores the async started flag.
*/
private boolean asyncStarted; // Note that asyncStarted is per async cycle, and resets when the request is dispatched
/**
* Stores the attribute manager.
*/
private AttributeManager attributeManager = new DefaultAttributeManager();
/**
* Stores the wrapper attributes.
*/
private List wrapperAttributes = new ArrayList<>();
/**
* Stores the wrapper parameters.
*/
private Map wrapperParameters = new HashMap<>();
/**
* Constructor.
*
* @param request the HTTP servlet request.
*/
public AsyncHttpDispatchWrapper(HttpServletRequest request) {
super(request);
wrapperAttributes.add("piranha.response");
}
@Override
public Map getModifiableParameterMap() {
return wrapperParameters;
}
@Override
public HttpServletRequest getRequest() {
return (HttpServletRequest) super.getRequest();
}
@Override
public DispatcherType getDispatcherType() {
return ASYNC;
}
@Override
public String getServletPath() {
return servletPath;
}
@Override
public String getPathInfo() {
return pathInfo;
}
@Override
public void setPathInfo(String pathInfo) {
this.pathInfo = pathInfo;
}
@Override
public String getRequestURI() {
return requestURI;
}
/**
* Set the request URI.
*
* @param requestURI the request URI.
*/
public void setRequestURI(String requestURI) {
this.requestURI = requestURI;
}
@Override
public String getQueryString() {
return queryString;
}
@Override
public AsyncContext startAsync() throws IllegalStateException {
return startAsync(this, requireNonNull((ServletResponse) getAttribute("piranha.response")));
}
@Override
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
if (asyncContext != null) {
throw new IllegalStateException("Async cycle has already been started");
}
servletRequest.setAttribute("CALLED_FROM_ASYNC_WRAPPER", "true");
asyncContext = super.startAsync(servletRequest, servletResponse);
asyncStarted = true;
return asyncContext;
}
@Override
public boolean isAsyncStarted() {
return asyncStarted;
}
@Override
public Enumeration getAttributeNames() {
HashSet attributeNames = new HashSet<>();
attributeNames.addAll(list(super.getAttributeNames()));
attributeNames.addAll(wrapperAttributes);
return enumeration(attributeNames);
}
@Override
public Object getAttribute(String name) {
if (wrapperAttributes.contains(name)) {
return attributeManager.getAttribute(name);
}
return super.getAttribute(name);
}
@Override
public void setAttribute(String name, Object object) {
if (wrapperAttributes.contains(name)) {
attributeManager.setAttribute(name, object);
} else {
super.setAttribute(name, object);
}
}
@Override
public void removeAttribute(String name) {
if (wrapperAttributes.contains(name)) {
attributeManager.removeAttribute(name);
} else {
super.removeAttribute(name);
}
}
/**
* Get the parameter.
*
* @param name the name.
* @return the value.
*/
@Override
public String getParameter(String name) {
if (getParameterValues(name) == null) {
return null;
}
return getParameterValues(name)[0];
}
/**
* {@return the parameter map}
*/
@Override
public Map getParameterMap() {
Map parameterMap = new HashMap<>();
parameterMap.putAll(super.getParameterMap());
parameterMap.putAll(wrapperParameters);
return unmodifiableMap(parameterMap);
}
/**
* {@return the parameter names}
*/
@Override
public Enumeration getParameterNames() {
HashSet parameterNames = new HashSet<>();
parameterNames.addAll(super.getParameterMap().keySet());
parameterNames.addAll(wrapperParameters.keySet());
return enumeration(parameterNames);
}
/**
* {@return the parameter values}
* @param name the parameter name.
*/
@Override
public String[] getParameterValues(String name) {
if (wrapperParameters.containsKey(name)) {
return wrapperParameters.get(name);
}
return super.getParameterValues(name);
}
@Override
public void setQueryString(String queryString) {
this.queryString = queryString;
}
/**
* Set as a wrapper attribute.
*
* @param name the name.
* @param value the value.
*/
public void setAsWrapperAttribute(String name, Object value) {
attributeManager.setAttribute(name, value);
}
/**
* {@return the wrapper attributes}
*/
public List getWrapperAttributes() {
return wrapperAttributes;
}
/**
* {@return the wrapper parameters}
*/
public Map getWrapperParameters() {
return wrapperParameters;
}
@Override
public void setDispatcherType(DispatcherType dispatcherType) {
// cannot change the dispatcher type.
}
@Override
public String toString() {
return getRequestURIWithQueryString() + " " + super.toString();
}
/**
* {@return the request URI with query string}
*/
public String getRequestURIWithQueryString() {
StringBuilder builder = new StringBuilder();
builder.append(getRequestURI());
if (getQueryString() != null) {
builder.append("?").append(queryString);
}
return builder.toString();
}
@Override
public void setContextPath(String contextPath) {
// cannot change the context path.
}
@Override
public void setServletPath(String servletPath) {
this.servletPath = servletPath;
}
@Override
public void setAuthType(String authType) {
// cannot be set.
}
@Override
public void setUserPrincipal(Principal userPrincipal) {
// cannot be set.
}
@Override
public void setWebApplication(WebApplication webApplication) {
// cannot be set.
}
@Override
public MultipartConfigElement getMultipartConfig() {
return null;
}
@Override
public void setAsyncSupported(boolean asyncSupported) {
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/AsyncNonHttpDispatchWrapper.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import jakarta.servlet.DispatcherType;
import static jakarta.servlet.DispatcherType.ASYNC;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletRequestWrapper;
/**
* The async non-HTTP dispatch wrapper.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class AsyncNonHttpDispatchWrapper extends ServletRequestWrapper {
/**
* Constructor.
*
* @param request the servlet request.
*/
public AsyncNonHttpDispatchWrapper(ServletRequest request) {
super(request);
}
@Override
public DispatcherType getDispatcherType() {
return ASYNC;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/CookieParser.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import jakarta.servlet.http.Cookie;
/**
* The Cookie parser
*/
public class CookieParser {
/**
* Stores the $Version= constant
*/
private static final String VERSION = "$Version=";
private CookieParser() {
}
/**
* Parse the Cookie header
*
* @param cookieValues the Cookie header, without "Cookie:"
* @return the {@link Cookie} array
* @throws NullPointerException if cookieValues is null
* @throws IllegalArgumentException if some cookie contains a illegal
* character
*/
public static Cookie[] parse(String cookieValues) {
Objects.requireNonNull(cookieValues);
if (cookieValues.startsWith(VERSION)) {
return parseRFC2109(cookieValues.substring(cookieValues.indexOf(';') + 1));
}
return parseNetscape(cookieValues);
}
private static Cookie[] parseNetscape(String cookiesValue) {
ArrayList cookieList = new ArrayList<>();
String[] cookieCandidates = cookiesValue.split(";");
for (String cookieCandidate : cookieCandidates) {
String[] cookieString = cookieCandidate.split("=");
String cookieName = cookieString[0].trim();
String cookieValue = null;
if (cookieString.length == 2) {
cookieValue = cookieString[1].trim();
}
Cookie cookie = new Cookie(cookieName, cookieValue);
cookieList.add(cookie);
}
return cookieList.toArray(Cookie[]::new);
}
@SuppressWarnings({"removal"})
private static Cookie[] parseRFC2109(String cookiesValue) {
List cookieList = new ArrayList<>();
String[] cookieCandidates = cookiesValue.split("[;,]");
Cookie currentCookie = null;
for (String cookieCandidate : cookieCandidates) {
String[] values = cookieCandidate.trim().split("=", 2);
String name = removeQuotes(values[0].trim());
String value = values.length == 2 ? removeQuotes(values[1].trim()) : null;
if (name.startsWith("$")) {
if (currentCookie == null) {
throw new IllegalArgumentException("Invalid Cookie");
}
if ("$Domain".equals(name)) {
currentCookie.setDomain(value);
cookieList.add(new Cookie(name, value));
} else if ("$Path".equals(name)) {
currentCookie.setPath(value);
cookieList.add(new Cookie(name, value));
}
} else {
currentCookie = new Cookie(name, value);
currentCookie.setVersion(1);
cookieList.add(currentCookie);
}
}
return cookieList.toArray(Cookie[]::new);
}
private static String removeQuotes(String value) {
Objects.requireNonNull(value);
if (value.startsWith("\"") && value.endsWith("\"")) {
return value.substring(1, value.length() - 1);
}
return value;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultAnnotationManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.AnnotationInfo;
import cloud.piranha.core.api.AnnotationManager;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* The default AnnotationManager.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultAnnotationManager implements AnnotationManager {
/**
* Stores the annotated classes.
*/
private HashMap, Set>> annotatedClasses = new HashMap<>();
/**
* Constructor.
*/
public DefaultAnnotationManager() {
}
@Override
public void addAnnotatedClass(Class extends Annotation> annotationClass, Class> clazz) {
if (annotationClass == null) {
throw new IllegalArgumentException("annotationClass cannot be null");
}
if (!annotatedClasses.containsKey(annotationClass)) {
HashSet> classes = new HashSet<>();
classes.add(clazz);
annotatedClasses.put(annotationClass, classes);
} else {
@SuppressWarnings({ "rawtypes", "unchecked" })
HashSet> classes = (HashSet) annotatedClasses.get(annotationClass);
classes.add(clazz);
}
}
@Override
public void addAnnotation(AnnotationInfo> annotationInfo) {
if (annotationInfo == null) {
throw new IllegalArgumentException("annotationInfo cannot be null");
}
}
@Override
public void addInstance(Class> instanceClass, Class> implementingClass) {
if (instanceClass == null) {
throw new IllegalArgumentException("instanceClass cannot be null");
}
}
@Override
public List> getAnnotations(Class annotationClass) {
return Collections.emptyList();
}
@Override
public List> getAnnotations(Class>... annotationClasses) {
return Collections.emptyList();
}
@Override
public List> getInstances(Class instanceClass) {
return Collections.emptyList();
}
@Override
public List> getInstances(Class>... instanceClasses) {
return Collections.emptyList();
}
@Override
public List> getAnnotationsByTarget(Class annotationClass, AnnotatedElement type) {
return Collections.emptyList();
}
@Override
public Set> getAnnotatedClass(Class extends Annotation> annotationClass) {
return annotatedClasses.getOrDefault(annotationClass, Collections.emptySet());
}
@SuppressWarnings("unchecked")
@Override
public Set> getAnnotatedClasses(Class>[] annotationClasses) {
HashSet> result = new HashSet<>();
if (annotationClasses != null) {
for (Class> annotationClass : annotationClasses) {
result.addAll(getAnnotatedClass((Class extends Annotation>) annotationClass));
}
}
return result;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultAsyncContext.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.AsyncManager;
import cloud.piranha.core.api.WebApplication;
import cloud.piranha.core.api.WebApplicationRequest;
import cloud.piranha.core.api.WebApplicationResponse;
import jakarta.servlet.AsyncContext;
import jakarta.servlet.AsyncEvent;
import jakarta.servlet.AsyncListener;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletRequestWrapper;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.ServletResponseWrapper;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.System.Logger;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.WARNING;
import java.util.ArrayList;
import java.util.List;
import static java.util.Objects.requireNonNull;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
/**
* The default AsyncContext.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultAsyncContext implements AsyncContext {
/**
* Stores the logger.
*/
private static final Logger LOGGER = System.getLogger(DefaultAsyncContext.class.getName());
/**
* Stores the listeners.
*/
private final List listeners = new ArrayList<>();
/**
* The request that comes from a call to request.startAsync()
*
*
* This is either the request the caller passed in when using
* request.startAsync(someRequest, someResponse) or it's the
* request object on which startAsync was called when using the
* zero argument version request.startAsync().
*
*
* In the latter case, the request is guaranteed to be the "original
* request", which is the request passed to the servlet that started the
* async cycle. In the former case it can either be the "original request",
* or it can be that request but wrapped by user code.
*/
private final ServletRequest asyncStartRequest;
/**
* The response that comes from a call to request.startAsync()
*
*
* This is either the response the caller passed in when using
* request.startAsync(someRequest, someResponse) or it's the
* response object associated with the request object on which
* startAsync was called when using the zero argument version
* request.startAsync().
*
*
* In the latter case, the response is guaranteed to be the "original
* response", which is the response passed to the servlet that started the
* async cycle. In the former case it can either be the "original response",
* or it can be that response but wrapped by user code.
*/
private final ServletResponse asyncStartResponse;
/**
* "the request object passed to the first servlet object in the call chain
* that received the request from the client."
*/
private final WebApplicationRequest originalRequest;
/**
* The response object passed to the first servlet object in the call chain
* that received the request from the client."
*/
private final WebApplicationResponse originalResponse;
/**
* Stores the timeout.
*/
private long timeout = Long.parseLong(System.getProperty("piranha.async.timeout", "30000")); // 30 seconds, as mandated by spec
/**
* Tracks whether dispatch() has already been called on this context or not.
*/
private boolean dispatched;
/**
* Stores the scheduled thread pool executor.
*/
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1);
/**
* Constructor.
*
* @param asyncStartRequest the servlet asyncStartRequest.
* @param asyncStartResponse the servlet asyncStartResponse.
*/
public DefaultAsyncContext(ServletRequest asyncStartRequest, ServletResponse asyncStartResponse) {
this.asyncStartRequest = requireNonNull(asyncStartRequest);
this.asyncStartResponse = requireNonNull(asyncStartResponse);
originalRequest = unwrapFully(asyncStartRequest);
originalResponse = unwrapFully(asyncStartResponse);
scheduledThreadPoolExecutor.schedule(this::onTimeOut, timeout, MILLISECONDS);
}
@Override
public void addListener(AsyncListener listener) {
this.listeners.add(listener);
}
@Override
public void addListener(AsyncListener listener, ServletRequest request, ServletResponse response) {
this.listeners.add(listener);
}
@Override
public T createListener(Class type) throws ServletException {
try {
return type.getConstructor().newInstance();
} catch (Throwable t) {
LOGGER.log(WARNING, () -> "Unable to create AsyncListener: " + type.getName(), t);
throw new ServletException("Unable to create listener", t);
}
}
/**
* @see AsyncContext#dispatch()
*/
@Override
public void dispatch() {
String path;
if (asyncStartRequest instanceof HttpServletRequest httpServletRequest) {
path = httpServletRequest.getRequestURI().substring(httpServletRequest.getContextPath().length());
} else {
path = originalRequest.getRequestURI().substring(originalRequest.getContextPath().length());
}
dispatch(path);
}
/**
* @see AsyncContext#dispatch(java.lang.String)
*/
@Override
public void dispatch(String path) {
dispatch(asyncStartRequest.getServletContext(), path);
}
/**
* Dispatch.
*
* @param servletContext the servlet context.
* @param path the path.
*/
@Override
public void dispatch(ServletContext servletContext, String path) {
if (dispatched) {
throw new IllegalStateException("Dispatch already called on this async contexct");
}
dispatched = true;
WebApplication webApplication = (WebApplication) servletContext;
AsyncManager asyncManager = webApplication.getManager().getAsyncManager();
asyncManager.getDispatcher(webApplication, path, asyncStartRequest, asyncStartResponse)
.dispatch();
}
@Override
public void complete() {
scheduledThreadPoolExecutor.shutdownNow();
LOGGER.log(DEBUG, () -> "Completing async processing");
if (!listeners.isEmpty()) {
listeners.forEach(listener -> {
try {
listener.onComplete(new AsyncEvent(this));
} catch (IOException ioe) {
LOGGER.log(WARNING, () -> "IOException when calling onComplete on AsyncListener", ioe);
}
});
}
LOGGER.log(DEBUG, () -> "Flushing async asyncStartResponse buffer");
try {
asyncStartResponse.flushBuffer();
} catch (IOException ioe) {
LOGGER.log(WARNING, () -> "IOException when flushing async asyncStartResponse buffer", ioe);
}
originalResponse.closeAsyncResponse();
}
/**
* Process on timeout
*/
public void onTimeOut() {
scheduledThreadPoolExecutor.shutdownNow();
if (!listeners.isEmpty()) {
listeners.forEach(listener -> {
try {
listener.onTimeout(new AsyncEvent(this));
} catch (IOException ioe) {
LOGGER.log(WARNING, () -> "IOException when calling onTimeout on AsyncListener", ioe);
}
});
}
LOGGER.log(DEBUG, () -> "Flushing async asyncStartResponse buffer");
if (!asyncStartResponse.isCommitted()) {
try {
asyncStartResponse.flushBuffer();
} catch (IOException ioe) {
LOGGER.log(WARNING, () -> "IOException when flushing async asyncStartResponse buffer", ioe);
}
}
originalResponse.closeAsyncResponse();
}
@Override
public ServletRequest getRequest() {
return asyncStartRequest;
}
@Override
public ServletResponse getResponse() {
return asyncStartResponse;
}
@Override
public long getTimeout() {
return timeout;
}
@Override
public boolean hasOriginalRequestAndResponse() {
return originalRequest == asyncStartRequest && originalResponse == asyncStartResponse;
}
@Override
public void setTimeout(long timeout) {
this.timeout = timeout;
}
/**
* Start the thread.
*
* @param runnable the runnable.
*/
@Override
public void start(Runnable runnable) {
LOGGER.log(DEBUG, "Starting async context with: {0}", runnable);
Thread thread = new Thread(runnable);
thread.start();
}
/**
* Unwrap the servlet request.
*
* @param the type.
* @param request the request to unwrap.
* @return the unwrapped request.
*/
@SuppressWarnings("unchecked")
private T unwrapFully(ServletRequest request) {
ServletRequest currentRequest = request;
while (currentRequest instanceof ServletRequestWrapper wrapper) {
currentRequest = wrapper.getRequest();
}
return (T) currentRequest;
}
/**
* Unwrap the servlet response.
*
* @param the type.
* @param response the response to unwrap.
* @return the unwrapped response.
*/
@SuppressWarnings("unchecked")
private T unwrapFully(ServletResponse response) {
ServletResponse currentResponse = response;
while (currentResponse instanceof ServletResponseWrapper wrapper) {
currentResponse = wrapper.getResponse();
}
return (T) currentResponse;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultAsyncDispatcher.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.AsyncDispatcher;
import cloud.piranha.core.api.WebApplication;
import jakarta.servlet.AsyncContext;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.System.Logger;
import static java.lang.System.Logger.Level.WARNING;
/**
* The default AsyncDispatcher.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultAsyncDispatcher implements AsyncDispatcher {
/**
* Stores the logger.
*/
private static final Logger LOGGER = System.getLogger(DefaultAsyncDispatcher.class.getName());
/**
* Stores the web application.
*/
private final WebApplication webApplication;
/**
* Stores the path.
*/
private final String path;
/**
* Stores the async start request.
*/
private final ServletRequest asyncStartRequest;
/**
* Stores the async start response.
*/
private final ServletResponse asyncStartResponse;
/**
* Constructor.
*
* @param webApplication the web application.
* @param path the path.
* @param asyncStartRequest the request.
* @param asyncStartResponse the asyncStartResponse.
*/
public DefaultAsyncDispatcher(WebApplication webApplication, String path, ServletRequest asyncStartRequest, ServletResponse asyncStartResponse) {
this.webApplication = webApplication;
this.path = path;
this.asyncStartRequest = asyncStartRequest;
this.asyncStartResponse = asyncStartResponse;
}
@Override
public void dispatch() {
AsyncContext asyncContext = asyncStartRequest.getAsyncContext();
RequestDispatcher requestDispatcher = webApplication.getRequestDispatcher(path);
new Thread(() -> {
Thread.currentThread().setContextClassLoader(webApplication.getClassLoader());
ServletRequest dispatchedRequest = addAsyncWrapper(asyncStartRequest);
try {
requestDispatcher.forward(dispatchedRequest, asyncStartResponse);
} catch (Throwable t) {
LOGGER.log(WARNING, "Error occurred during dispatch", t);
}
if (!dispatchedRequest.isAsyncStarted()) {
asyncContext.complete();
}
}).start();
}
private ServletRequest addAsyncWrapper(ServletRequest request) {
if (request instanceof HttpServletRequest httpServletRequest) {
return new AsyncHttpDispatchWrapper(httpServletRequest);
}
return new AsyncNonHttpDispatchWrapper(request);
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultAsyncManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.AsyncDispatcher;
import cloud.piranha.core.api.AsyncManager;
import cloud.piranha.core.api.WebApplication;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
/**
* The default implementation of the AsyncManager API.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultAsyncManager implements AsyncManager {
/**
* Constructor.
*/
public DefaultAsyncManager() {
}
@Override
public AsyncDispatcher getDispatcher(WebApplication webApplication, String path, ServletRequest asyncStartRequest, ServletResponse asyncStartResponse) {
return new DefaultAsyncDispatcher(webApplication, path, asyncStartRequest, asyncStartResponse);
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultAttributeManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.AttributeManager;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* The default AttributeManager.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultAttributeManager implements AttributeManager {
/**
* Stores the attributes.
*/
protected Map attributes;
/**
* Constructor.
*/
public DefaultAttributeManager() {
attributes = new ConcurrentHashMap<>();
}
@Override
public Object getAttribute(String name) {
return attributes.get(name);
}
@Override
public Enumeration getAttributeNames() {
return Collections.enumeration(attributes.keySet());
}
@Override
public void removeAttribute(String name) {
attributes.remove(name);
}
@Override
public void setAttribute(String name, Object value) {
if (value != null) {
attributes.put(name, value);
} else {
attributes.remove(name);
}
}
@Override
public boolean containsAttribute(String name) {
return attributes.containsKey(name);
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultAuthenticatedIdentity.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import static java.util.Collections.unmodifiableSet;
import java.security.Principal;
import java.util.HashSet;
import java.util.Set;
import javax.security.auth.Subject;
import cloud.piranha.core.api.AuthenticatedIdentity;
/**
* Default implementation of AuthenticatedIdentity.
*
*
* This implementation is an immutable structure, with a facility to store it in
* TLS. It's the responsibility of the context, e.g. the HTTP request handler,
* to remove the identity from TLS at the end of the context (e.g. end of the
* HTTP request), or at any other appropriate time (e.g. when logging out
* mid-request).
*
*
* @author Arjan Tijms
*
*/
public class DefaultAuthenticatedIdentity implements AuthenticatedIdentity {
/**
* Stores the current identity.
*/
private static InheritableThreadLocal currentIdentity = new InheritableThreadLocal<>();
/**
* Stores the current subject.
*/
private static InheritableThreadLocal currentSubject = new InheritableThreadLocal<>();
/**
* Stores the caller principal.
*/
private Principal callerPrincipal;
/**
* Stores the groups.
*/
private Set groups = new HashSet<>();
/**
* Constructor.
*
* @param callerPrincipal the caller principal.
* @param groups the groups.
*/
public DefaultAuthenticatedIdentity(Principal callerPrincipal, Set groups) {
this.callerPrincipal = callerPrincipal;
this.groups = unmodifiableSet(groups);
}
/**
* Set the current identity.
*
* @param callerPrincipal the caller principal.
* @param groups the groups.
*/
public static void setCurrentIdentity(Principal callerPrincipal, Set groups) {
setCurrentIdentity(new DefaultAuthenticatedIdentity(callerPrincipal, groups));
}
/**
* Set the current identity.
*
* @param identity the identity.
*/
public static void setCurrentIdentity(AuthenticatedIdentity identity) {
Subject subject = new Subject();
subject.getPrincipals().add(identity);
if (identity.getCallerPrincipal() != null) {
subject.getPrincipals().add(identity.getCallerPrincipal());
}
currentIdentity.set(identity);
currentSubject.set(subject);
}
/**
* {@return the current subject}
*/
public static Subject getCurrentSubject() {
return currentSubject.get();
}
/**
* {@return the current identity}
*/
public static AuthenticatedIdentity getCurrentIdentity() {
return currentIdentity.get();
}
/**
* Clear identity and subject.
*/
public static void clear() {
currentIdentity.remove();
currentSubject.remove();
}
@Override
public Principal getCallerPrincipal() {
return callerPrincipal;
}
@Override
public Set getGroups() {
return groups;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultCurrentRequestHolder.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.CurrentRequestHolder;
import jakarta.servlet.http.HttpServletRequest;
/**
* Default implementation of the CurrentRequestHolder interface.
*
* @author Arjan Tijms
*
*/
public class DefaultCurrentRequestHolder implements CurrentRequestHolder {
/**
* Stores the HTTP servlet request.
*/
private HttpServletRequest request;
/**
* Constructor.
*
* @param request the HTTP servlet request.
*/
public DefaultCurrentRequestHolder(HttpServletRequest request) {
this.request = request;
}
@SuppressWarnings("unchecked")
@Override
public T getRequest() {
return (T) request;
}
@Override
public void setRequest(HttpServletRequest request) {
this.request = request;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultDispatcherManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.DispatcherManager;
import cloud.piranha.core.api.ServletEnvironment;
import cloud.piranha.core.api.WebApplication;
import jakarta.servlet.RequestDispatcher;
/**
* The default DispatcherManager.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultDispatcherManager implements DispatcherManager {
/**
* Stores the web application.
*/
private WebApplication webApplication;
/**
* Constructor.
*/
public DefaultDispatcherManager() {
}
@Override
public RequestDispatcher getNamedDispatcher(String name) {
RequestDispatcher dispatcher = null;
ServletEnvironment environment = (ServletEnvironment) webApplication
.getServletRegistration(name);
if (environment != null) {
dispatcher = new DefaultNamedRequestDispatcher(environment);
}
return dispatcher;
}
@Override
public void setWebApplication(WebApplication webApplication) {
this.webApplication = webApplication;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultErrorPageManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.ErrorPageManager;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/**
* The default ErrorPageManager.
*
* @author Arjan Tijms
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultErrorPageManager implements ErrorPageManager {
/**
* Stores the error pages by code.
*/
private final Map errorPagesByCode = new HashMap<>();
/**
* Stores the error pages by exception.
*/
private final Map errorPagesByException = new HashMap<>();
/**
* Constructor.
*/
public DefaultErrorPageManager() {
}
@Override
public void addErrorPage(int statusCode, String page) {
errorPagesByCode.put(statusCode, page);
}
@Override
public void addErrorPage(String throwableClassName, String page) {
errorPagesByException.put(throwableClassName, page);
}
@Override
public String getErrorPage(Throwable exception, HttpServletResponse httpResponse) {
if (exception != null) {
Class> rootException = exception.getClass();
String page = null;
while (rootException != null && page == null) {
page = errorPagesByException.get(rootException.getName());
rootException = rootException.getSuperclass();
}
if (page == null && exception instanceof ServletException servletException) {
page = getErrorPage(servletException.getRootCause(), httpResponse);
}
return page;
}
if (httpResponse.getStatus() >= 400) {
return errorPagesByCode.get(httpResponse.getStatus());
}
// No error
return null;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultFilterChain.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.ServletInvocation;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.UnavailableException;
import jakarta.servlet.http.HttpServletResponse;
import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import java.io.IOException;
import java.lang.System.Logger;
import static java.lang.System.Logger.Level.TRACE;
/**
* The default FilterChain.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultFilterChain implements FilterChain {
/**
* Stores the logger.
*/
private static final Logger LOGGER
= System.getLogger(DefaultFilterChain.class.getName());
/**
* Stores the filter.
*/
private Filter filter;
/**
* Stores the next filter chain.
*/
private FilterChain nextFilterChain;
/**
* Stores the servlet.
*/
private Servlet servlet;
/**
* Stores the servlet invocation.
*/
private ServletInvocation servletInvocation;
/**
* Constructor.
*/
public DefaultFilterChain() {
}
/**
* Constructor.
*
* @param servletInvocation the servlet invocation.
* @param servlet the servlet.
*/
public DefaultFilterChain(ServletInvocation servletInvocation, Servlet servlet) {
this.servletInvocation = servletInvocation;
this.servlet = servlet;
}
/**
* Constructor.
*
* @param filter the filter.
* @param nextFilterChain the next filter chain.
*/
public DefaultFilterChain(Filter filter, FilterChain nextFilterChain) {
this.filter = filter;
this.nextFilterChain = nextFilterChain;
}
/**
* Process the request.
*
* @param request the request.
* @param response the response.
* @throws IOException when an I/O error occurs.
* @throws ServletException when a servlet error occurs.
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if (filter != null) {
if (LOGGER.isLoggable(TRACE)) {
LOGGER.log(TRACE, "Calling filter: {0}", filter);
}
filter.doFilter(request, response, nextFilterChain);
if (LOGGER.isLoggable(TRACE)) {
LOGGER.log(TRACE, "Called filter: {0}", filter);
}
} else if (servlet != null) {
if (LOGGER.isLoggable(TRACE)) {
LOGGER.log(TRACE, "Calling servlet: {0}", servlet);
}
request.setAttribute(DefaultServletEnvironment.class.getName(), servlet.getServletConfig());
try {
servlet.service(request, response);
} finally {
request.removeAttribute(DefaultServletEnvironment.class.getName());
}
if (LOGGER.isLoggable(TRACE)) {
LOGGER.log(TRACE, "Called servlet: {0}", servlet);
}
} else if (servletInvocation != null && servletInvocation.isServletUnavailable()) {
// We've reached the servlet, but the servlet is not available (for instance because
// the init method failed)
Exception exception;
Throwable throwable = servletInvocation.getServletEnvironment().getUnavailableException();
if (throwable instanceof Exception e) {
exception = e;
} else {
exception = new UnavailableException("");
exception.initCause(throwable);
}
if (response instanceof HttpServletResponse httpServletResponse) {
httpServletResponse.setStatus(500);
}
if (LOGGER.isLoggable(TRACE)) {
LOGGER.log(TRACE, "The servlet: {0} is unavailable, because of: {1}",
servletInvocation.getServletName(),
servletInvocation.getServletEnvironment().getUnavailableException());
}
request.setAttribute("piranha.request.exception", exception);
throw new ServletException(exception);
} else if (response instanceof HttpServletResponse httpServletResponse) {
if (LOGGER.isLoggable(TRACE)) {
LOGGER.log(TRACE,
"We did not find a proper filter chain for request: {0} and response: {1}",
request, response);
}
httpServletResponse.sendError(SC_NOT_FOUND);
}
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultFilterEnvironment.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.FilterEnvironment;
import cloud.piranha.core.api.WebApplication;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
/**
* The default FilterEnvironment.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultFilterEnvironment implements FilterEnvironment {
/**
* Stores the async supported flag.
*/
private boolean asyncSupported;
/**
* Stores the class name.
*/
private String className;
/**
* Stores the filter.
*/
private Filter filter;
/**
* Stores the filter name.
*/
private String filterName;
/**
* Stores the init parameters.
*/
private HashMap initParameters;
/**
* Stores the servlet mame mappings.
*/
private ConcurrentHashMap servletNameMappings;
/**
* Stores the status.
*/
private int status;
/**
* Stores the url pattern mappings.
*/
private ConcurrentHashMap urlPatternMappings;
/**
* Stores the web application.
*/
private WebApplication webApplication;
/**
* Constructor.
*/
public DefaultFilterEnvironment() {
initParameters = new HashMap<>();
servletNameMappings = new ConcurrentHashMap<>();
urlPatternMappings = new ConcurrentHashMap<>();
}
/**
* Constructor.
*
* @param webApp the web application.
* @param filterName the filter name.
* @param filter the filter.
*/
public DefaultFilterEnvironment(WebApplication webApp, String filterName, Filter filter) {
this();
this.webApplication = webApp;
this.filterName = filterName;
this.filter = filter;
this.className = filter.getClass().getName();
}
@Override
public void addMappingForServletNames(EnumSet dispatcherTypes, boolean isMatchAfter, String... servletNames) {
String[] names = Stream.of(servletNames).map(s -> "servlet:// " + s).toArray(String[]::new);
webApplication.addFilterMapping(dispatcherTypes, filterName, isMatchAfter, names);
Arrays.stream(servletNames).forEach(x -> servletNameMappings.put(x, filterName));
}
@Override
public void addMappingForUrlPatterns(EnumSet dispatcherTypes, boolean isMatchAfter, String... urlPatterns) {
webApplication.addFilterMapping(dispatcherTypes, filterName, isMatchAfter, urlPatterns);
Arrays.stream(urlPatterns).forEach(x -> urlPatternMappings.put(x, filterName));
}
@Override
public String getClassName() {
return className;
}
@Override
public Filter getFilter() {
return filter;
}
@Override
public String getFilterName() {
return filterName;
}
@Override
public String getInitParameter(String name) {
return initParameters.get(name);
}
@Override
public Enumeration getInitParameterNames() {
return Collections.enumeration(initParameters.keySet());
}
@Override
public Map getInitParameters() {
return initParameters;
}
@Override
public String getName() {
return filterName;
}
@Override
public ServletContext getServletContext() {
return this.webApplication;
}
@Override
public Collection getServletNameMappings() {
return Collections.unmodifiableCollection(servletNameMappings.keySet());
}
/**
* Get the status.
*
* @return the status.
*/
public int getStatus() {
return status;
}
@Override
public Collection getUrlPatternMappings() {
return Collections.unmodifiableCollection(urlPatternMappings.keySet());
}
@Override
public WebApplication getWebApplication() {
return webApplication;
}
@Override
public void initialize() throws ServletException {
if (filter == null) {
try {
Class extends Filter> clazz = webApplication.getClassLoader().loadClass(className).asSubclass(Filter.class);
filter = webApplication.createFilter(clazz);
} catch (Throwable throwable) {
throw new ServletException("Unable to initialize the filter", throwable);
}
}
}
@Override
public boolean isAsyncSupported() {
return asyncSupported;
}
@Override
public void setAsyncSupported(boolean asyncSupported) {
this.asyncSupported = asyncSupported;
}
@Override
public void setClassName(String className) {
this.className = className;
}
@Override
public void setFilterName(String filterName) {
this.filterName = filterName;
}
@Override
public boolean setInitParameter(String name, String value) {
boolean result = false;
if (!initParameters.containsKey(name)) {
initParameters.put(name, value);
result = true;
}
return result;
}
@Override
public Set setInitParameters(Map initParameters) {
HashSet conflicting = new HashSet<>();
if (initParameters != null) {
initParameters.entrySet().forEach(entry -> {
String name = entry.getKey();
String value = entry.getValue();
if (name == null) {
throw new IllegalArgumentException("A null name is not allowed");
}
if (value == null) {
throw new IllegalArgumentException("A null value is not allowed");
}
if (!setInitParameter(name, value)) {
conflicting.add(name);
}
});
}
return conflicting;
}
@Override
public void setStatus(int status) {
this.status = status;
}
@Override
public void setWebApplication(WebApplication webApplication) {
this.webApplication = webApplication;
}
@Override
public String toString() {
return
(className != null? className : "") + " " +
(!urlPatternMappings.isEmpty()? urlPatternMappings : "") +
(!servletNameMappings.isEmpty()? servletNameMappings : "") + " " +
super.toString();
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultFilterMapping.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.FilterMapping;
import jakarta.servlet.DispatcherType;
import static jakarta.servlet.DispatcherType.REQUEST;
import java.util.Objects;
/**
* The default FilterMapping.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultFilterMapping implements FilterMapping {
/**
* Stores the dispatcher type.
*/
private final DispatcherType dispatcherType;
/**
* Stores the filter name.
*/
private final String filterName;
/**
* Stores the URL pattern.
*/
private final String urlPattern;
/**
* Constructor.
*
* @param filterName the filter name.
* @param urlPattern the URL pattern.
*/
public DefaultFilterMapping(String filterName, String urlPattern) {
this(REQUEST, filterName, urlPattern);
}
/**
* Constructor.
*
* @param dispatcherType the dispatcher type.
* @param filterName the filter name.
* @param urlPattern the URL pattern.
*/
public DefaultFilterMapping(DispatcherType dispatcherType, String filterName, String urlPattern) {
this.dispatcherType = dispatcherType;
this.filterName = filterName;
this.urlPattern = urlPattern;
}
@Override
public boolean equals(Object object) {
boolean result = false;
if (object instanceof DefaultFilterMapping mapping
&& mapping.filterName.equals(filterName)
&& mapping.urlPattern.equals(urlPattern)
&& mapping.dispatcherType.equals(dispatcherType)) {
result = true;
}
return result;
}
@Override
public DispatcherType getDispatcherType() {
return dispatcherType;
}
@Override
public String getFilterName() {
return filterName;
}
@Override
public String getUrlPattern() {
return urlPattern;
}
@Override
public int hashCode() {
int hash = 7;
hash = 83 * hash + Objects.hashCode(this.filterName);
hash = 83 * hash + Objects.hashCode(this.urlPattern);
return hash;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultHttpHeader.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.HttpHeader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
/**
* The default HttpHeader.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultHttpHeader implements HttpHeader {
/**
* Stores the name.
*/
private final String name;
/**
* Stores the values.
*/
private final ArrayList values = new ArrayList<>();
/**
* Constructor.
*
* @param name the name.
* @param value the value.
*/
public DefaultHttpHeader(String name, String value) {
this.name = name;
values.add(value);
}
/**
* Add the value.
*
* @param value the value to add.
*/
@Override
public void addValue(String value) {
values.add(value);
}
/**
* {@return the name}
*/
@Override
public String getName() {
return this.name;
}
/**
* {@return the value}
*/
@Override
public String getValue() {
return values.get(0);
}
/**
* {@return the values}
*/
@Override
public Enumeration getValues() {
return Collections.enumeration(values);
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultHttpHeaderManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.HttpHeaderManager;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
/**
* The default HttpHeaderManager.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultHttpHeaderManager implements HttpHeaderManager {
/**
* Stores the headers.
*/
protected final HashMap headers;
/**
* Stores the Locale.
*/
private Locale locale;
/**
* Constructor.
*/
@SuppressWarnings("deprecation")
public DefaultHttpHeaderManager() {
headers = new HashMap<>();
locale = new Locale("en", "US", "ISO-8859-1");
}
@Override
public void addHeader(String name, String value) {
if (headers.containsKey(name.toUpperCase(locale))) {
headers.get(name.toUpperCase(locale)).addValue(value);
} else {
DefaultHttpHeader header = new DefaultHttpHeader(name, value);
headers.put(name.toUpperCase(locale), header);
}
}
@Override
public boolean containsHeader(String name) {
return headers.containsKey(name.toUpperCase(locale));
}
@Override
public long getDateHeader(String name) throws IllegalArgumentException {
long result = -1;
if (headers.containsKey(name.toUpperCase(locale))) {
DefaultHttpHeader header = headers.get(name.toUpperCase(locale));
try {
String value = header.getValue();
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", locale);
result = format.parse(value).getTime();
} catch (ParseException exception) {
throw new IllegalArgumentException(
"Cannot convert header to a date", exception);
}
}
return result;
}
@Override
public String getHeader(String name) {
String result = null;
if (headers.containsKey(name.toUpperCase(locale))) {
result = headers.get(name.toUpperCase(locale)).getValue();
}
return result;
}
@Override
public Enumeration getHeaderNames() {
List names = new ArrayList<>();
for (DefaultHttpHeader header : headers.values()) {
names.add(header.getName());
}
return Collections.enumeration(names);
}
@Override
public Enumeration getHeaders(String name) {
Enumeration result = Collections.enumeration(Collections.emptyList());
if (headers.containsKey(name.toUpperCase(locale))) {
result = headers.get(name.toUpperCase(locale)).getValues();
}
return result;
}
@Override
public int getIntHeader(String name) throws NumberFormatException {
int result = -1;
if (headers.containsKey(name.toUpperCase(locale))) {
DefaultHttpHeader header = headers.get(name.toUpperCase(locale));
try {
result = Integer.parseInt(header.getValue());
} catch (NumberFormatException exception) {
throw new NumberFormatException(
"Cannot convert header to an int");
}
}
return result;
}
@Override
public void removeHeader(String name) {
headers.remove(name.toUpperCase());
}
@Override
public void setHeader(String name, String value) {
DefaultHttpHeader header = new DefaultHttpHeader(name, value);
headers.put(name.toUpperCase(locale), header);
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultHttpServletMapping.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import jakarta.servlet.http.HttpServletMapping;
import jakarta.servlet.http.MappingMatch;
/**
* The default HttpServletMapping.
*
* @author Arjan Tijms
*/
public class DefaultHttpServletMapping implements HttpServletMapping {
/**
* Stores the MappingMatch
*/
private MappingMatch mappingMatch;
/**
* Stores the matchValue
*
*/
private String matchValue;
/**
* Stores the pattern
*/
private String pattern;
/**
* Stores the servletName
*/
private String servletName;
/**
* Constructor.
*/
public DefaultHttpServletMapping() {
}
@Override
public MappingMatch getMappingMatch() {
return mappingMatch;
}
/**
* Set the mapping match.
*
* @param mappingMatch the mappingMatch to set
*/
public void setMappingMatch(MappingMatch mappingMatch) {
this.mappingMatch = mappingMatch;
}
@Override
public String getMatchValue() {
return matchValue;
}
/**
* Set the matchValue.
*
* @param matchValue the matchValue to set
*/
public void setMatchValue(String matchValue) {
this.matchValue = matchValue;
}
@Override
public String getPattern() {
return pattern;
}
/**
* Set the pattern.
*
* @param pattern the pattern to set
*/
public void setPattern(String pattern) {
this.pattern = pattern;
}
@Override
public String getServletName() {
return servletName;
}
/**
* Set the servlet name.
*
* @param servletName the servletName to set
*/
public void setServletName(String servletName) {
this.servletName = servletName;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultHttpSession.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.HttpSessionManager;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSession;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.UUID;
/**
* The default HttpSession.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultHttpSession implements HttpSession {
/**
* Stores the attributes.
*/
private final HashMap attributes = new HashMap<>();
/**
* Stores the creation time.
*/
private final long creationTime;
/**
* Stores the session id.
*/
private String id;
/**
* Stores the last accessed time.
*/
private long lastAccessedTime;
/**
* Stores the max inactive interval.
*/
private int maxInactiveInterval;
/**
* Stores if the session is new.
*/
private boolean newFlag;
/**
* Stores the servlet context.
*/
private ServletContext servletContext;
/**
* Stores the HTTP session manager.
*/
private HttpSessionManager sessionManager;
/**
* Stores the valid flag.
*/
private boolean valid;
/**
* Constructor.
*
* @param servletContext the servlet context.
*/
public DefaultHttpSession(ServletContext servletContext) {
this.id = UUID.randomUUID().toString();
this.servletContext = servletContext;
this.creationTime = System.currentTimeMillis();
this.lastAccessedTime = System.currentTimeMillis();
this.valid = true;
}
/**
* Constructor.
*
* @param servletContext the servlet context.
* @param id the id.
* @param newFlag the new flag.
*/
public DefaultHttpSession(ServletContext servletContext, String id, boolean newFlag) {
this.id = id;
this.servletContext = servletContext;
this.newFlag = newFlag;
this.creationTime = System.currentTimeMillis();
this.lastAccessedTime = System.currentTimeMillis();
this.valid = true;
}
@Override
public Object getAttribute(String name) {
verifyValid("getAttribute");
return this.attributes.get(name);
}
@Override
public Enumeration getAttributeNames() {
verifyValid("getAttributeNames");
return Collections.enumeration(attributes.keySet());
}
@Override
public long getCreationTime() {
verifyValid("getCreationTime");
return this.creationTime;
}
@Override
public String getId() {
return this.id;
}
@Override
public long getLastAccessedTime() {
verifyValid("getLastAccessedTime");
return this.lastAccessedTime;
}
@Override
public int getMaxInactiveInterval() {
return this.maxInactiveInterval;
}
@Override
public ServletContext getServletContext() {
return servletContext;
}
@Override
public void invalidate() {
verifyValid("invalidate");
sessionManager.destroySession(this);
this.valid = false;
}
@Override
public boolean isNew() {
verifyValid("isNew");
return this.newFlag;
}
@Override
public void removeAttribute(String name) {
verifyValid("removeAttribute");
sessionManager.attributeRemoved(this, name, attributes.remove(name));
}
@Override
public void setAttribute(String name, Object value) {
verifyValid("setAttribute");
if (value != null) {
boolean added = true;
if (attributes.containsKey(name)) {
added = false;
}
Object oldValue = attributes.put(name, value);
if (added) {
sessionManager.attributeAdded(this, name, value);
} else {
sessionManager.attributeReplaced(this, name, oldValue, value);
}
} else {
removeAttribute(name);
}
}
/**
* Set the id.
*
* @param id the id.
*/
public void setId(String id) {
this.id = id;
}
@Override
public void setMaxInactiveInterval(int maxInactiveInterval) {
this.maxInactiveInterval = maxInactiveInterval;
}
/**
* Set the new flag.
*
* @param newFlag the new flag.
*/
public void setNew(boolean newFlag) {
verifyValid("setNew");
this.newFlag = newFlag;
}
/**
* Set the HTTP session manager.
*
* @param sessionManager the HTTP session manager.
*/
public void setSessionManager(HttpSessionManager sessionManager) {
this.sessionManager = sessionManager;
}
/**
* Verify if the session is valid.
*
* @param methodName the method name.
*/
private void verifyValid(String methodName) {
if (!valid) {
throw new IllegalStateException("Session is invalid, called by: " + methodName);
}
}
/**
* Set the last accessed time.
*
* @param lastAccessedTime the last accessed time.
*/
public void setLastAccessedTime(long lastAccessedTime) {
this.lastAccessedTime = lastAccessedTime;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultHttpSessionManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.HttpSessionManager;
import cloud.piranha.core.api.WebApplication;
import jakarta.servlet.ServletRequestEvent;
import jakarta.servlet.ServletRequestListener;
import jakarta.servlet.SessionCookieConfig;
import jakarta.servlet.SessionTrackingMode;
import static jakarta.servlet.SessionTrackingMode.COOKIE;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpSessionAttributeListener;
import jakarta.servlet.http.HttpSessionBindingEvent;
import jakarta.servlet.http.HttpSessionBindingListener;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionIdListener;
import jakarta.servlet.http.HttpSessionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.EventListener;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* The default HttpSessionManager.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultHttpSessionManager implements HttpSessionManager, SessionCookieConfig, ServletRequestListener {
/**
* Stores the session listeners.
*/
protected final ArrayList attributeListeners;
/**
* Stores the comment.
*/
protected String comment;
/**
* Stores the default session tracking modes.
*/
protected final Set defaultSessionTrackingModes;
/**
* Stores the domain.
*/
protected String domain;
/**
* Stores the HTTP only flag.
*/
protected boolean httpOnly;
/**
* Stores the session id listeners.
*/
protected final ArrayList idListeners;
/**
* Stores the max age.
*/
protected int maxAge;
/**
* Stores the name.
*/
protected String name;
/**
* Stores the path.
*/
protected String path;
/**
* Stores the secure flag.
*/
protected boolean secure;
/**
* Stores the session counters.
*/
protected final Map sessionCounters = new HashMap<>();
/**
* Stores the cookie attributes.
*/
protected HashMap sessionCookieAttributes;
/**
* Stores the session listeners.
*/
protected final ArrayList sessionListeners;
/**
* Stores the session timeout (in minutes).
*/
protected int sessionTimeout;
/**
* Stores the session tracking modes.
*/
protected Set sessionTrackingModes;
/**
* Stores the sessions.
*/
protected Map sessions;
/**
* Stores the web application.
*/
protected WebApplication webApplication;
/**
* Constructor.
*/
public DefaultHttpSessionManager() {
attributeListeners = new ArrayList<>(1);
sessionCookieAttributes = new HashMap<>();
defaultSessionTrackingModes = EnumSet.of(COOKIE);
sessionTrackingModes = defaultSessionTrackingModes;
idListeners = new ArrayList<>(1);
name = "JSESSIONID";
sessionListeners = new ArrayList<>(1);
sessionTimeout = 10;
maxAge = -1;
sessions = new ConcurrentHashMap<>();
ThreadFactory threadFactory = (Runnable r) -> {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
};
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, threadFactory);
scheduler.scheduleWithFixedDelay(this::reapSessions, 0, 1300, MILLISECONDS);
}
@Override
public void addListener(T listener) {
if (listener instanceof HttpSessionAttributeListener httpSessionAttributeListener) {
attributeListeners.add(httpSessionAttributeListener);
}
if (listener instanceof HttpSessionIdListener httpSessionIdListener) {
idListeners.add(httpSessionIdListener);
}
if (listener instanceof HttpSessionListener httpSessionListener) {
sessionListeners.add(httpSessionListener);
}
}
@Override
public void attributeAdded(HttpSession session, String name, Object value) {
attributeListeners.stream().forEach(listener -> listener.attributeAdded(new HttpSessionBindingEvent(session, name, value)));
if (value instanceof HttpSessionBindingListener httpSessionBindingListener) {
httpSessionBindingListener.valueBound(new HttpSessionBindingEvent(session, name));
}
}
@Override
public void attributeRemoved(HttpSession session, String name, Object value) {
attributeListeners.stream().forEach(listener -> listener.attributeRemoved(new HttpSessionBindingEvent(session, name, value)));
if (value instanceof HttpSessionBindingListener httpSessionBindingListener) {
httpSessionBindingListener.valueUnbound(new HttpSessionBindingEvent(session, name));
}
}
@Override
public void attributeReplaced(HttpSession session, String name, Object oldValue, Object newValue) {
attributeListeners.stream().forEach(listener -> listener.attributeReplaced(new HttpSessionBindingEvent(session, name, oldValue)));
if (oldValue instanceof HttpSessionBindingListener httpSessionBindingListener) {
httpSessionBindingListener.valueUnbound(new HttpSessionBindingEvent(session, name));
}
if (newValue instanceof HttpSessionBindingListener httpSessionBindingListener) {
httpSessionBindingListener.valueBound(new HttpSessionBindingEvent(session, name));
}
}
@Override
public String changeSessionId(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
throw new IllegalStateException("No session active");
}
String oldSessionId = session.getId();
sessions.remove(oldSessionId);
String sessionId = UUID.randomUUID().toString();
DefaultHttpSession newSession = (DefaultHttpSession) session;
newSession.setId(sessionId);
sessions.put(sessionId, session);
idListeners.stream().forEach(idListener -> idListener.sessionIdChanged(new HttpSessionEvent(session), oldSessionId));
return sessionId;
}
@Override
@SuppressWarnings({"removal"})
public synchronized HttpSession createSession(HttpServletRequest request) {
String sessionId = UUID.randomUUID().toString();
DefaultHttpSession session = new DefaultHttpSession(webApplication, sessionId, true);
session.setMaxInactiveInterval(getSessionTimeout() * 60);
session.setSessionManager(this);
sessions.put(sessionId, session);
sessionCounters.put(session.getId(), new AtomicInteger(1));
HttpServletResponse response = (HttpServletResponse) webApplication.getResponse(request);
Cookie cookie = new Cookie(name, sessionId);
if (path != null) {
cookie.setPath(path);
} else {
cookie.setPath("".equals(request.getContextPath()) ? "/" : request.getContextPath());
}
cookie.setComment(comment);
if (domain != null) {
cookie.setDomain(domain);
}
cookie.setHttpOnly(httpOnly);
cookie.setMaxAge(maxAge);
cookie.setSecure(secure);
response.addCookie(cookie);
sessionListeners.stream().forEach(sessionListener -> sessionListener.sessionCreated(new HttpSessionEvent(session)));
return session;
}
@Override
public synchronized void destroySession(HttpSession session) {
for (HttpSessionListener sessionListener : sessionListeners) {
sessionListener.sessionDestroyed(new HttpSessionEvent(session));
}
sessions.remove(session.getId());
sessionCounters.remove(session.getId());
Iterator attributeNames = session.getAttributeNames().asIterator();
while(attributeNames.hasNext()) {
String attributeName = attributeNames.next();
attributeRemoved(session, attributeName, session.getAttribute(attributeName));
}
}
@Override
public String encodeRedirectURL(HttpServletResponse response, String url) {
return url;
}
@Override
public String encodeURL(HttpServletResponse response, String url) {
return url;
}
@Override
@SuppressWarnings("removal")
public String getComment() {
return comment;
}
@Override
public Set getDefaultSessionTrackingModes() {
return Collections.unmodifiableSet(defaultSessionTrackingModes);
}
@Override
public String getDomain() {
return domain;
}
@Override
public Set getEffectiveSessionTrackingModes() {
return Collections.unmodifiableSet(sessionTrackingModes);
}
@Override
public int getMaxAge() {
return maxAge;
}
@Override
public String getName() {
return name;
}
@Override
public String getPath() {
return path;
}
@Override
public HttpSession getSession(HttpServletRequest request, String currentSessionId) {
return sessions.get(currentSessionId);
}
@Override
public SessionCookieConfig getSessionCookieConfig() {
return this;
}
@Override
public int getSessionTimeout() {
return sessionTimeout;
}
@Override
public boolean hasSession(String sessionId) {
boolean result = false;
if (sessionId != null) {
result = sessions.containsKey(sessionId);
}
return result;
}
@Override
public boolean isHttpOnly() {
return httpOnly;
}
@Override
public boolean isSecure() {
return secure;
}
/**
* Reap any inactive session.
*/
protected void reapSessions() {
ArrayList keys = new ArrayList<>();
keys.addAll(sessions.keySet());
keys.forEach(sessionId -> {
HttpSession session = sessions.get(sessionId);
if (session != null) {
synchronized (session) {
if (sessionCounters.getOrDefault(session.getId(), new AtomicInteger(0)).intValue() <= 0) {
try {
if (session.getLastAccessedTime() + (session.getMaxInactiveInterval() * 1000L) - 1300 < System.currentTimeMillis()) {
session.invalidate();
}
} catch (IllegalStateException ise) {
// nothing to do
}
}
}
}
});
}
@Override
@SuppressWarnings("removal")
public void setComment(String comment) {
if (webApplication.isInitialized()) {
throw new IllegalStateException("You cannot call setComment once ServletContext is initialized");
}
}
@Override
public void setDomain(String domain) {
if (webApplication.isInitialized()) {
throw new IllegalStateException("You cannot call setDomain once ServletContext is initialized");
}
this.domain = domain;
}
@Override
public void setHttpOnly(boolean httpOnly) {
if (webApplication.isInitialized()) {
throw new IllegalStateException("You cannot call setHttpOnly once ServletContext is initialized");
}
this.httpOnly = httpOnly;
}
@Override
public void setMaxAge(int maxAge) {
if (webApplication.isInitialized()) {
throw new IllegalStateException("You cannot call setMaxAge once ServletContext is initialized");
}
this.maxAge = maxAge;
}
@Override
public void setName(String name) {
if (webApplication.isInitialized()) {
throw new IllegalStateException("You cannot call setName once ServletContext is initialized");
}
this.name = name;
}
@Override
public void setPath(String path) {
if (webApplication.isInitialized()) {
throw new IllegalStateException("You cannot call setPath once ServletContext is initialized");
}
this.path = path;
}
@Override
public void setSecure(boolean secure) {
if (webApplication.isInitialized()) {
throw new IllegalStateException("You cannot call setSecure once ServletContext is initialized");
}
this.secure = secure;
}
@Override
public void setSessionTimeout(int sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
@Override
public void setSessionTrackingModes(Set sessionTrackingModes) {
if (sessionTrackingModes.size() > 1 && sessionTrackingModes.contains(SessionTrackingMode.SSL)) {
throw new IllegalArgumentException("SSL cannot be combined with any other method");
}
this.sessionTrackingModes = Collections.unmodifiableSet(sessionTrackingModes);
}
@Override
public void setWebApplication(WebApplication webApplication) {
this.webApplication = webApplication;
}
@Override
public void requestInitialized(ServletRequestEvent event) {
if (event.getServletRequest() instanceof HttpServletRequest httpRequest) {
HttpSession session = httpRequest.getSession(false);
if (session != null) {
synchronized (session) {
AtomicInteger integer = sessionCounters.get(session.getId());
if (integer != null) {
integer.incrementAndGet();
}
}
}
}
}
@Override
public void requestDestroyed(ServletRequestEvent event) {
if (event.getServletRequest() instanceof HttpServletRequest httpRequest) {
HttpSession session = httpRequest.getSession(false);
if (session != null) {
synchronized (session) {
AtomicInteger integer = sessionCounters.get(session.getId());
if (integer != null) {
integer.decrementAndGet();
}
}
}
}
}
/*
REVIEW FOR SERVLET 6
*/
@Override
public void setAttribute(String name, String value) {
if (name == null) {
throw new IllegalArgumentException("name is null");
}
if (webApplication.isInitialized()) {
throw new IllegalStateException("You cannot call setAttribute once ServletContext is initialized");
}
String nameLowerCase = name.toLowerCase(Locale.ROOT);
switch (nameLowerCase) {
case "comment" -> setComment(value);
case "path" -> setPath(value);
case "name" -> setName(value);
case "domain" -> setDomain(value);
case "max-age" -> setMaxAge(Integer.parseInt(value));
case "secure" -> setSecure(Boolean.parseBoolean(value));
case "httponly" -> setHttpOnly(Boolean.parseBoolean(value));
default -> sessionCookieAttributes.put(name, value);
}
}
/*
REVIEW FOR SERVLET 6
*/
@Override
public String getAttribute(String name) {
String nameLowerCase = name.toLowerCase(Locale.ROOT);
return switch (nameLowerCase) {
case "comment" -> getComment();
case "path" -> getPath();
case "name" -> getName();
case "domain" -> getDomain();
case "max-age" -> String.valueOf(getMaxAge());
case "secure" -> String.valueOf(isSecure());
case "httponly" -> String.valueOf(isHttpOnly());
default -> sessionCookieAttributes.get(name);
};
}
@Override
public Map getAttributes() {
Stream> entriesWithGettersAndSetter = Stream.of(
Map.entry("Comment", getComment()),
Map.entry("Path", getPath()),
Map.entry("Name", getName()),
Map.entry("Domain", getDomain()),
Map.entry("Max-Age", String.valueOf(getMaxAge())),
Map.entry("HttpOnly", String.valueOf(isHttpOnly())),
Map.entry("Secure", String.valueOf(isSecure()))
);
return Stream.concat(entriesWithGettersAndSetter, sessionCookieAttributes.entrySet().stream())
.collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue));
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultInvocationFinder.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import static jakarta.servlet.DispatcherType.REQUEST;
import static jakarta.servlet.http.MappingMatch.DEFAULT;
import static jakarta.servlet.http.MappingMatch.EXACT;
import static jakarta.servlet.http.MappingMatch.EXTENSION;
import static jakarta.servlet.http.MappingMatch.PATH;
import static java.util.Collections.reverse;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import cloud.piranha.core.api.FilterEnvironment;
import cloud.piranha.core.api.FilterPriority;
import cloud.piranha.core.api.ServletEnvironment;
import cloud.piranha.core.api.WebApplicationRequestMapping;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.FilterChain;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import java.lang.System.Logger;
import static java.lang.System.Logger.Level.TRACE;
/**
* The invocation finder tries to find a servlet invocation matching a request
* for a path based or name based dispatch.
*
*
* Invocations returned by this finder take into account the various mappings,
* filters, welcome files and the default servlet.
*
* @author Arjan Tijms
*/
public class DefaultInvocationFinder {
/**
* Stores the logger.
*/
private static final Logger LOGGER
= System.getLogger(DefaultInvocationFinder.class.getName());
/**
* Stores the web application.
*/
private final DefaultWebApplication webApplication;
/**
* Constructor.
*
* @param webApplication the web application.
*/
public DefaultInvocationFinder(DefaultWebApplication webApplication) {
this.webApplication = webApplication;
}
/**
* Find the servlet invocation by path.
*
* @param servletPath the servlet path.
* @param pathInfo the path info.
* @return the servlet invocation.
* @throws IOException when an I/O error occurs.
* @throws ServletException when a Servlet error occurs.
*/
public DefaultServletInvocation findServletInvocationByPath(String servletPath, String pathInfo) throws IOException, ServletException {
return findServletInvocationByPath(REQUEST, servletPath, pathInfo);
}
/**
* Find the servlet invocation by path.
*
* @param dispatcherType the dispatcher type.
* @param servletPath the servlet path.
* @param pathInfo the path info.
* @return the servlet invocation.
* @throws IOException when an I/O error occurs.
* @throws ServletException when a Servlet error occurs.
*/
public DefaultServletInvocation findServletInvocationByPath(DispatcherType dispatcherType, String servletPath, String pathInfo) throws IOException, ServletException {
if (LOGGER.isLoggable(TRACE)) {
LOGGER.log(TRACE, "Find servlet invocation by path");
LOGGER.log(TRACE, "DispatcherType: {0}", dispatcherType.name());
LOGGER.log(TRACE, "Servlet path: {0}", servletPath);
LOGGER.log(TRACE, "Path info: {0}", pathInfo);
}
DefaultServletInvocation servletInvocation = getDirectServletInvocationByPath(servletPath, pathInfo);
if (servletInvocation == null) {
if (dispatcherType == REQUEST) {
servletInvocation = getWelcomeFileServletInvocation(servletPath, pathInfo != null ? pathInfo : "/");
if (servletInvocation == null) {
String servletPathLower = servletPath != null ? servletPath.toLowerCase() : "";
if (servletPathLower.startsWith("/web-inf") || servletPathLower.startsWith("/meta-inf")) {
servletInvocation = getDefaultServletInvocation(null, null);
} else {
servletInvocation = getDefaultServletInvocation(servletPath, pathInfo);
}
}
} else {
// Note: no WEB-INF checks needed here
servletInvocation = getDefaultServletInvocation(servletPath, pathInfo);
}
}
// Seed the chain with the servlet, if any. REQUEST dispatches can be done to only a filter so a servlet is not hard requirement
servletInvocation.seedFilterChain();
return addFilters(dispatcherType, servletInvocation, servletPath, pathInfo);
}
/**
* Add the filters.
*
* @param dispatcherType the dispatcher type.
* @param servletInvocation the servlet invocation.
* @param servletPath the servlet path.
* @param pathInfo the path info.
* @return the servlet invocation.
*/
public DefaultServletInvocation addFilters(DispatcherType dispatcherType, DefaultServletInvocation servletInvocation, String servletPath, String pathInfo) {
if (dispatcherType == null) {
// If there's no dispatcher type, don't add filters. This can happen when the dispatch is not yet known
// so as with the request dispatcher, which first gets the resource, and only after that gets to be used for a forward or include.
return servletInvocation;
}
List filterEnvironments
= findFilterEnvironments(
dispatcherType,
// Look at the servletInvocation if there is one, as a welcome file can be set
// that differs from the request path
servletInvocation == null ? servletPath : servletInvocation.getServletPath(),
servletInvocation == null ? pathInfo : servletInvocation.getPathInfo(),
servletInvocation == null ? null : servletInvocation.getServletName());
if (filterEnvironments != null) {
if (servletInvocation == null) {
servletInvocation = new DefaultServletInvocation();
servletInvocation.setServletPath(servletPath);
servletInvocation.setPathInfo(pathInfo);
}
servletInvocation.setFilterEnvironments(filterEnvironments);
servletInvocation.setFilterChain(findFilterChain(filterEnvironments, servletInvocation.getFilterChain()));
}
return servletInvocation;
}
/**
* Find the servlet invocation by servlet name.
*
* @param servletName the servlet name.
* @return the servlet invocation, or null if not found.
*/
public DefaultServletInvocation findServletInvocationByName(String servletName) {
ServletEnvironment servletEnvironment = webApplication.servletEnvironments.get(servletName);
if (servletEnvironment == null) {
return null;
}
DefaultServletInvocation servletInvocation = new DefaultServletInvocation();
servletInvocation.setServletName(servletName);
servletInvocation.setServletEnvironment(servletEnvironment);
servletInvocation.seedFilterChain();
servletInvocation.setFromNamed(true);
return servletInvocation;
}
private DefaultServletInvocation getDirectServletInvocationByPath(String servletPath, String pathInfo) {
String path = addOrRemoveSlashIfNeeded(servletPath + (pathInfo == null ? "" : pathInfo));
WebApplicationRequestMapping mapping = webApplication.webApplicationRequestMapper.findServletMapping(path);
if (mapping == null) {
return null;
}
String servletName = webApplication.webApplicationRequestMapper.getServletName(mapping.getPattern());
if (servletName == null) {
return null;
}
ServletEnvironment servletEnvironment = webApplication.servletEnvironments.get(servletName);
if (servletEnvironment == null) {
return null;
}
DefaultServletInvocation servletInvocation = new DefaultServletInvocation();
servletInvocation.setInvocationPath(path);
servletInvocation.setApplicationRequestMapping(mapping);
servletInvocation.setServletName(servletName);
servletInvocation.setServletEnvironment(servletEnvironment);
servletInvocation.getHttpServletMapping().setMappingMatch(
mapping.isExact() ? EXACT
: mapping.isExtension() ? EXTENSION
: PATH);
servletInvocation.getHttpServletMapping().setPattern(mapping.getPattern());
servletInvocation.getHttpServletMapping().setServletName(servletName);
servletInvocation.getHttpServletMapping().setMatchValue(mapping.getMatchValue());
if (mapping.isExact()) {
servletInvocation.setServletPath(path);
servletInvocation.setPathInfo(null);
} else if (!mapping.isExtension()) {
servletInvocation.setServletPath(mapping.getPattern().substring(0, mapping.getPattern().length() - 2));
String newPathInfo = path.substring(mapping.getPattern().length() - 2);
servletInvocation.setPathInfo(newPathInfo.isEmpty() ? null : newPathInfo);
} else {
servletInvocation.setServletPath(servletPath);
servletInvocation.setPathInfo(pathInfo);
}
return servletInvocation;
}
private DefaultServletInvocation getWelcomeFileServletInvocation(String servletPath, String pathInfo) throws IOException {
if (webApplication.getManager().getWelcomeFileManager() != null) {
for (String welcomeFile : webApplication.getManager().getWelcomeFileManager().getWelcomeFileList()) {
DefaultServletInvocation servletInvocation = null;
if (isJsp(welcomeFile)) {
// .jsp files are special in the system, as they are mapped to a servlet, but also
// have to be present at exactly that path as static resource. Additionally we have
// the required index.jsp welcome file, that may not actually be there.
// So, .jsp files are treated as a servlet invocation but only if the static resource exists
if (isStaticResource(servletPath, pathInfo + welcomeFile)) {
servletInvocation = getDirectServletInvocationByPath(servletPath, pathInfo + welcomeFile);
}
} else if (isStaticResource(servletPath, pathInfo + welcomeFile)) {
// If we have a welcome file, we can load it via the default servlet.
return getDefaultServletInvocation(servletPath, pathInfo + welcomeFile);
} else {
// Try if we have a welcome servlet
servletInvocation = getDirectServletInvocationByPath(servletPath, pathInfo + welcomeFile);
}
if (servletInvocation != null) {
servletInvocation.setOriginalServletPath(servletPath);
return servletInvocation;
}
}
// No static file, JSP or servlet
}
return null;
}
private boolean isStaticResource(String servletPath, String pathInfo) throws MalformedURLException {
return webApplication.getResource(addOrRemoveSlashIfNeeded(servletPath + (pathInfo == null ? "" : pathInfo))) != null;
}
private static boolean isJsp(String welcomeFile) {
return welcomeFile.endsWith(".jsp");
}
private String addOrRemoveSlashIfNeeded(String string) {
if (string.startsWith("/")) {
if (string.startsWith("//")) {
return string.substring(1);
}
return string;
}
return "/" + string;
}
private DefaultServletInvocation getDefaultServletInvocation(String servletPath, String pathInfo) {
ServletEnvironment servletEnvironment = null;
String servletName = webApplication.webApplicationRequestMapper.getDefaultServlet();
if (servletName != null) {
servletEnvironment = webApplication.servletEnvironments.get(servletName);
}
if (servletEnvironment == null) {
Servlet defaultServlet = webApplication.defaultServlet;
if (defaultServlet == null) {
defaultServlet = new DefaultServlet();
}
servletName = "default";
servletEnvironment = new DefaultServletEnvironment(webApplication, servletName, defaultServlet);
}
DefaultServletInvocation servletInvocation = new DefaultServletInvocation();
servletInvocation.setServletName(servletName);
servletInvocation.setServletEnvironment(servletEnvironment);
// 12.2
// A string containing only the "/" character indicates the "default" servlet of the application.
// In this case the servlet path is the request URI minus the context path and the path info is null.
servletInvocation.setServletPath(servletPath == null ? null : addOrRemoveSlashIfNeeded(servletPath + (pathInfo == null ? "" : pathInfo)));
servletInvocation.setInvocationPath(servletPath); // look at whether its really needed to have path and invocation path
servletInvocation.setPathInfo(null);
servletInvocation.getHttpServletMapping().setMappingMatch(DEFAULT);
servletInvocation.getHttpServletMapping().setMatchValue("");
servletInvocation.getHttpServletMapping().setPattern("/");
servletInvocation.getHttpServletMapping().setServletName(servletName);
return servletInvocation;
}
/**
* Find the filter environments.
*
* @param dispatcherType the dispatcher type.
* @param servletPath the servlet path to which filters should apply.
* @param pathInfo the path info to which filters should apply.
* @param servletName name of the servlet to be filtered, if any. Can be
* null.
*
* @return the filter environments.
*/
protected List findFilterEnvironments(DispatcherType dispatcherType, String servletPath, String pathInfo, String servletName) {
List filterEnvironments = null;
String path = servletPath + (pathInfo == null ? "" : pathInfo);
Collection filterNames = webApplication.webApplicationRequestMapper.findFilterMappings(dispatcherType, path);
if (servletName != null) {
String servletNamePath = "servlet:// " + servletName;
filterNames.addAll(webApplication.webApplicationRequestMapper.findFilterMappings(dispatcherType, servletNamePath));
}
if (!filterNames.isEmpty()) {
filterEnvironments = new ArrayList<>();
for (String filterName : filterNames) {
if (webApplication.filters.get(filterName) != null) {
filterEnvironments.add(webApplication.filters.get(filterName));
}
}
}
return filterEnvironments;
}
private FilterChain findFilterChain(List filterEnvironments, FilterChain initialFilterChain) {
List prioritisedFilters = filterEnvironments.stream()
.filter(e -> e.getFilter() instanceof FilterPriority)
.sorted(this::sortOnPriority)
.toList();
List notPrioritisedFilters = filterEnvironments.stream()
.filter(e -> !(e.getFilter() instanceof FilterPriority))
.toList();
List currentEnvironments = new ArrayList<>();
currentEnvironments.addAll(prioritisedFilters);
currentEnvironments.addAll(notPrioritisedFilters);
reverse(currentEnvironments);
FilterChain downFilterChain = initialFilterChain;
FilterChain upFilterChain;
for (FilterEnvironment filterEnvironment : currentEnvironments) {
upFilterChain = new DefaultFilterChain(filterEnvironment.getFilter(), downFilterChain);
downFilterChain = upFilterChain;
}
return downFilterChain;
}
private int sortOnPriority(FilterEnvironment x, FilterEnvironment y) {
FilterPriority filterX = (FilterPriority) x.getFilter();
FilterPriority filterY = (FilterPriority) y.getFilter();
return Integer.compare(filterX.getPriority(), filterY.getPriority());
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultJspConfigDescriptor.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import jakarta.servlet.descriptor.JspConfigDescriptor;
import jakarta.servlet.descriptor.JspPropertyGroupDescriptor;
import jakarta.servlet.descriptor.TaglibDescriptor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* The default JspConfigDescriptor.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultJspConfigDescriptor implements JspConfigDescriptor {
/**
* Stores the taglibs.
*/
private List taglibs = new ArrayList<>();
/**
* Constructor.
*/
public DefaultJspConfigDescriptor() {
}
@Override
public Collection getTaglibs() {
return taglibs;
}
@Override
public Collection getJspPropertyGroups() {
return new ArrayList<>();
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultJspManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.JspManager;
import cloud.piranha.core.api.WebApplication;
import jakarta.servlet.ServletRegistration;
import jakarta.servlet.descriptor.JspConfigDescriptor;
/**
* The default JspManager.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultJspManager implements JspManager {
/**
* Stores the JSP config descriptor.
*/
private JspConfigDescriptor descriptor;
/**
* Constructor.
*/
public DefaultJspManager() {
}
@Override
public ServletRegistration.Dynamic addJspFile(WebApplication webApplication, String servletName, String jspFile) {
return null;
}
@Override
public JspConfigDescriptor getJspConfigDescriptor() {
return descriptor;
}
@Override
public void setJspConfigDescriptor(JspConfigDescriptor descriptor) {
this.descriptor = descriptor;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultLocaleEncodingManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.LocaleEncodingManager;
import java.util.HashMap;
import java.util.Map;
/**
* The default LocaleEncodingManager.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultLocaleEncodingManager implements LocaleEncodingManager {
/**
* Stores the locale mappings.
*/
private final Map localeMappings;
/**
* Constructor.
*/
public DefaultLocaleEncodingManager() {
localeMappings = new HashMap<>(1);
/*
* TODO - We have added the "ja" locale as a default locale encoding
* mapping for now as the TCK test seems the require it. Note
* that we should evaluate if the TCK test should be
* challenged.
*
* See com/sun/ts/tests/servlet/api/jakarta_servlet_http/httpservletresponse/URLClient.java#setCharacterEncodingTest
*/
localeMappings.put("ja", "Shift_Jis");
}
@Override
public void addCharacterEncoding(String locale, String encoding) {
localeMappings.put(locale, encoding);
}
@Override
public String getCharacterEncoding(String locale) {
return localeMappings.get(locale);
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultModuleFinder.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.resource.api.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.lang.System.Logger.Level;
import java.lang.System.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.WARNING;
import static java.util.stream.Collectors.toSet;
/**
* Provides an implementation of {@link ModuleFinder} to work
* with {@link Resource}
* @author Thiago Henrique Hupner
*/
public class DefaultModuleFinder implements ModuleFinder {
/**
* Stores the logger
*/
private static final Logger LOGGER = System.getLogger(DefaultModuleFinder.class.getName());
/**
* Stores the attribute Automatic-Module-Name
*/
private static final Attributes.Name AUTOMATIC_MODULE_NAME
= new Attributes.Name("Automatic-Module-Name");
/**
* Stores the dash version pattern
*/
private static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))");
/**
* Stores the non alphanumeric pattern
*/
private static final Pattern NON_ALPHANUMERIC = Pattern.compile("[^A-Za-z0-9]");
/**
* Stores the repeating dots pattern
*/
private static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+");
/**
* Stores the leading dots pattern
*/
private static final Pattern LEADING_DOTS = Pattern.compile("^\\.");
/**
* Stores the trailing dots pattern
*/
private static final Pattern TRAILING_DOTS = Pattern.compile("\\.$");
/**
* Stores the cache for the modules already resolved
*/
private final Map cachedModuleReferences = new HashMap<>();
/**
* Store the resources
*/
private final List resources;
/**
* Stores the searched flag
*/
private boolean searched = false;
/**
* Constructor
* @param resources the resources
*/
public DefaultModuleFinder(List resources) {
this.resources = resources;
}
@Override
public Optional find(String name) {
ModuleReference moduleReference = cachedModuleReferences.get(name);
if (moduleReference != null) {
return Optional.of(moduleReference);
}
searchAllModules();
return Optional.ofNullable(cachedModuleReferences.get(name));
}
private String getModuleName(Resource resource, String resourceName) {
String automaticModuleName = deriveAutomaticModuleNameFromManifest(resource);
return normalizeModuleName(automaticModuleName != null ? automaticModuleName : cleanModuleName(resourceName));
}
private ModuleDescriptor moduleDescriptorFromResource(Resource resource) {
ModuleDescriptor moduleInfo = moduleInfo(resource);
if (moduleInfo != null){
if (LOGGER.isLoggable(DEBUG)) {
LOGGER.log(DEBUG, () -> "Module " + moduleInfo.toNameAndVersion() + " from resource: " + resource.getName() + " (module-info.class)");
LOGGER.log(DEBUG,() -> "Package exported by module " + moduleInfo.name() + ": " + moduleInfo.exports());
moduleInfo.provides().stream().map(x -> "Module provides " + x.service() + "with " + x.providers()).forEach(x -> LOGGER.log(DEBUG, x));
moduleInfo.uses().stream().map(x -> "Module uses " + x).forEach(x -> LOGGER.log(DEBUG, x));
}
return moduleInfo;
}
String name = resource.getName().replace(".jar", "");
String versionString = null;
// find first occurrence of -${NUMBER}. or -${NUMBER}$
Matcher matcher = DASH_VERSION.matcher(name);
if (matcher.find()) {
int start = matcher.start();
// attempt to parse the tail as a version string
try {
String tail = name.substring(start + 1);
ModuleDescriptor.Version.parse(tail);
versionString = tail;
} catch (IllegalArgumentException ignore) {
// nothing to do here.
}
name = name.substring(0, start);
}
String moduleName = getModuleName(resource, name);
String version = versionString;
LOGGER.log(DEBUG, () -> "Module " + moduleName + ((version != null)? "@" + version : "") + " from " + resource.getName());
ModuleDescriptor.Builder builder = ModuleDescriptor.newAutomaticModule(moduleName);
if (version != null)
builder.version(version);
Set packages = packages(resource);
LOGGER.log(DEBUG, () -> "Packages exported by module " + moduleName + ": " + packages);
builder.packages(packages);
addProviders(builder, resource);
return builder.build();
}
private void addProviders(ModuleDescriptor.Builder builder, Resource resource) {
Set providers = resource.getAllLocations()
.filter(x -> x.startsWith("/META-INF/services/") && !x.endsWith("/"))
.collect(toSet());
for (String providerFile : providers) {
InputStream inputStream = resource.getResourceAsStream(providerFile);
if (inputStream == null)
continue;
@SuppressWarnings("resource")
List providerList = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))
.lines()
.filter(x -> !x.startsWith("#"))
.filter(x -> !x.isEmpty())
.toList();
if (!providerList.isEmpty()) {
String serviceName = providerFile.substring("/META-INF/services/".length());
LOGGER.log(DEBUG, () -> "Module provides " + serviceName + " with " + providerList);
builder.provides(serviceName, providerList);
}
}
}
private Set packages(Resource resource) {
return resource.getAllLocations()
.filter(x -> x.endsWith(".class"))
.filter(x -> !x.startsWith("/META-INF"))
.map(x -> x.substring(1))
.map(this::toPackageName)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toSet());
}
private String normalizeModuleName(String module) {
StringBuilder result = new StringBuilder();
for (String part : module.split("\\.")) {
if (!Character.isJavaIdentifierStart(part.charAt(0))) {
result.append("$").append(part);
} else {
result.append(part);
}
result.append(".");
}
return result.deleteCharAt(result.length() - 1).toString();
}
private Optional toPackageName(String name) {
int index = name.lastIndexOf("/");
if (index > 0) {
return Optional.of(name.substring(0,
index).replace('/', '.'));
} else {
return Optional.empty();
}
}
private ModuleDescriptor moduleInfo(Resource resource) {
// Need to parse MRJARs
try (InputStream moduleInfo = resource.getResourceAsStream("module-info.class")) {
if (moduleInfo != null) {
// We have a module-info
return ModuleDescriptor.read(moduleInfo, () -> packages(resource));
}
} catch (IOException e) {
// nothing to do here.
}
return null;
}
private String deriveAutomaticModuleNameFromManifest(Resource resource) {
try (InputStream manifestInputStream = resource.getResourceAsStream("META-INF/MANIFEST.MF")) {
if (manifestInputStream == null)
return null;
Manifest man = new Manifest(manifestInputStream);
Attributes attrs = man.getMainAttributes();
if (attrs != null) {
return attrs.getValue(AUTOMATIC_MODULE_NAME);
}
} catch (IOException e) {
// nothing to do here.
}
return null;
}
private void searchAllModules() {
if (searched)
return;
searched = true;
Map packageToExporter = new HashMap<>();
for (Resource resource : resources) {
try {
ModuleDescriptor moduleDescriptor = moduleDescriptorFromResource(resource);
if (hasSplitPackages(packageToExporter, moduleDescriptor)) {
continue;
}
cachedModuleReferences.put(moduleDescriptor.name(), new DefaultModuleReference(moduleDescriptor, URI.create("resource://" + resource.getName()), resource));
} catch (Exception e) {
LOGGER.log(Level.WARNING, () -> "Resource " + resource.getName() + " will not be treated as a module: " + e);
}
}
}
private boolean hasSplitPackages(Map packageToExporter, ModuleDescriptor moduleDescriptor) {
for (String aPackage : moduleDescriptor.packages()) {
String previousModuleName = packageToExporter.put(aPackage, moduleDescriptor.name());
if (previousModuleName != null) {
LOGGER.log(WARNING, () ->
"Modules %s and %s export package %s, they will be part of the unnamed module"
.formatted(moduleDescriptor.name(), previousModuleName, aPackage));
cachedModuleReferences.remove(previousModuleName);
packageToExporter.remove(aPackage);
return true;
}
}
return false;
}
@Override
public Set findAll() {
searchAllModules();
return Set.copyOf(cachedModuleReferences.values());
}
/**
* Clean up candidate module name derived from a JAR file name.
*
* @param mn the module name to cleanup.
* @return the cleaned module name.
*/
private static String cleanModuleName(String mn) {
// replace non-alphanumeric
mn = NON_ALPHANUMERIC.matcher(mn).replaceAll(".");
// collapse repeating dots
mn = REPEATING_DOTS.matcher(mn).replaceAll(".");
// drop leading dots
if (!mn.isEmpty() && mn.charAt(0) == '.')
mn = LEADING_DOTS.matcher(mn).replaceAll("");
// drop trailing dots
int len = mn.length();
if (len > 0 && mn.charAt(len-1) == '.')
mn = TRAILING_DOTS.matcher(mn).replaceAll("");
return mn;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultModuleLayerProcessor.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.ModuleLayerProcessor;
import java.lang.System.Logger;
import static java.lang.System.Logger.Level.WARNING;
/**
* The module layer processor
* @author Thiago Henrique Hupner
*/
public enum DefaultModuleLayerProcessor implements ModuleLayerProcessor {
/**
* Singleton instance
*/
INSTANCE;
/**
* Stores the add opens property
*
* The format is: module.source/package=module.target (, module.source/package=module.target)*
*
*/
private static final String ADD_OPENS = "cloud.piranha.modular.add-opens";
/**
* Stores the add opens property
*
* The format is: module.source/package=module.target (, module.source/package=module.target)*
*
*/
private static final String ADD_EXPORTS = "cloud.piranha.modular.add-exports";
/**
* Stores the add opens property
*
* The format is: module.source=module.target (, module.source=module.target)*
*
*/
private static final String ADD_READS = "cloud.piranha.modular.add-reads";
/**
* Stores the logger
*/
private static final Logger LOGGER = System.getLogger(DefaultModuleLayerProcessor.class.getName());
@Override
public void processModuleLayerOptions(ModuleLayer.Controller controller) {
ModuleLayer moduleLayer = controller.layer();
String opens = System.getProperty(ADD_OPENS);
if (opens != null) {
addExportsOrOpens(opens, moduleLayer, controller, true);
}
String exports = System.getProperty(ADD_EXPORTS);
if (exports != null) {
addExportsOrOpens(exports, moduleLayer, controller, false);
}
String reads = System.getProperty(ADD_READS);
if (reads != null) {
addReads(reads, moduleLayer, controller);
}
}
private static void logModuleNotFound(String option, String module) {
LOGGER.log(WARNING, () -> "Ignoring option " + option + " because module " + module + " was not found");
}
private static void addReads(String property, ModuleLayer moduleLayer, ModuleLayer.Controller controller) {
for (String readsOption : property.trim().split(",")) {
// module.source=module.target
String[] parts = readsOption.trim().split("[=]", 2);
String sourceName = parts[0].trim();
String targetName = parts[1].trim();
Module source = moduleLayer.findModule(sourceName).orElse(null);
Module target = moduleLayer.findModule(targetName).orElse(null);
if (source == null || target == null) {
logModuleNotFound(readsOption, source == null ? sourceName : targetName);
continue;
}
try {
// When the source module is inside the application layer
controller.addReads(source, target);
} catch (IllegalArgumentException ignored) {
// When the source module is in the boot layer
source.addReads(target);
}
}
}
private static void addExportsOrOpens(String property, ModuleLayer moduleLayer, ModuleLayer.Controller controller, boolean opens) {
for (String option : property.trim().split(",")) {
// module.source/package=module.target
String[] parts = option.trim().split("[/=]", 3);
String sourceName = parts[0].trim();
String aPackage = parts[1].trim();
String targetName = parts[2].trim();
Module source = moduleLayer.findModule(sourceName).orElse(null);
Module target = moduleLayer.findModule(targetName).orElse(null);
if (source == null || target == null) {
logModuleNotFound(option, source == null ? sourceName : targetName);
continue;
}
try {
// When the source module is inside the application layer
if (opens) {
controller.addOpens(source, aPackage, target);
} else {
controller.addExports(source, aPackage, target);
}
} catch (IllegalArgumentException ignored) {
// When the source module is in the boot layer
if (opens) {
source.addOpens(aPackage, target);
} else {
source.addExports(aPackage, target);
}
}
}
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultModuleReader.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.resource.api.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.lang.module.ModuleReader;
import java.net.URI;
import java.net.URL;
import java.util.Optional;
import java.util.stream.Stream;
/**
* Provides an implementation of {@link ModuleReader} to work
* with {@link Resource}
* @author Thiago Henrique Hupner
*/
public class DefaultModuleReader implements ModuleReader {
/**
* Stores the resources
*/
private final Resource resource;
/**
* Constructor
* @param resource the resource
*/
public DefaultModuleReader(Resource resource) {
this.resource = resource;
}
@Override
public Optional find(String name) throws IOException {
try {
return Optional.of(resource.getResource(name).toURI());
} catch (Exception e) {
return Optional.empty();
}
}
@Override
public Optional open(String name) throws IOException {
// It was needed to override because the default implementation
// opens the URL from an URI, so it loses its StreamHandler
// and tries to load any resource from the GlobalArchiveStreamHandler
URL url = resource.getResource(name);
if (url != null)
return Optional.of(url.openStream());
return Optional.empty();
}
@Override
public Stream list() throws IOException {
return resource.getAllLocations().map(x -> x.startsWith("/") ? x.substring(1) : x);
}
@Override
public void close() throws IOException {
// nothing to do here.
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultModuleReference.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.resource.api.Resource;
import java.io.IOException;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
import java.net.URI;
/**
* Provides an implementation of {@link ModuleReference} to work
* with {@link Resource}
*
* @author Thiago Henrique Hupner
*/
public class DefaultModuleReference extends ModuleReference {
/**
* Stores the resource
*/
private final Resource resource;
/**
* Constructor
*
* @param descriptor the descriptor
* @param location the location
* @param resource the resource
*/
public DefaultModuleReference(ModuleDescriptor descriptor, URI location, Resource resource) {
super(descriptor, location);
this.resource = resource;
}
@Override
public ModuleReader open() throws IOException {
return new DefaultModuleReader(resource);
}
Resource getResource() {
return resource;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultMultiPartManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.MultiPartManager;
import cloud.piranha.core.api.WebApplication;
import cloud.piranha.core.api.WebApplicationRequest;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Part;
import java.util.Collection;
import java.util.Collections;
/**
* The default MultiPartManager.
*
*
* This MultiPartManager is a no-op.
*
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultMultiPartManager implements MultiPartManager {
/**
* Constructor.
*/
public DefaultMultiPartManager() {
}
@Override
public Collection getParts(WebApplication webApplication, WebApplicationRequest request) throws ServletException {
return Collections.emptyList();
}
@Override
public Part getPart(WebApplication webApplication, WebApplicationRequest request, String name) throws ServletException {
return null;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultNamedRequestDispatcher.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.ServletEnvironment;
import cloud.piranha.core.api.WebApplicationRequest;
import cloud.piranha.core.api.WebApplicationResponse;
import jakarta.servlet.DispatcherType;
import static jakarta.servlet.DispatcherType.FORWARD;
import static jakarta.servlet.DispatcherType.INCLUDE;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletRequestWrapper;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.ServletResponseWrapper;
import java.io.IOException;
import java.io.OutputStream;
/**
* The default named RequestDispatcher.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultNamedRequestDispatcher implements RequestDispatcher {
/**
* Stores the Servlet environment.
*/
private final ServletEnvironment environment;
/**
* Constructor.
*
* @param environment the Servlet environment.
*/
public DefaultNamedRequestDispatcher(ServletEnvironment environment) {
this.environment = environment;
}
@Override
public void forward(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
WebApplicationRequest request = unwrap(servletRequest);
WebApplicationResponse response = unwrap(servletResponse);
/* - JAVADOC
*
* If the response is already committed throw an IllegalStateException.
*/
if (servletResponse.isCommitted()) {
throw new IllegalStateException("Response has already been committed");
}
/* - JAVADOC, Servlet:SPEC:77
*
* Clear uncommitted output in the response buffer before forwarding
*/
servletResponse.resetBuffer();
/* - JAVADOC
*
* Sets the dispatcher type of the given request to DispatcherType.FORWARD.
*/
DispatcherType dispatcherType = request.getDispatcherType();
request.setDispatcherType(FORWARD);
environment.getServlet().service(servletRequest, servletResponse);
/* - Servlet:SPEC:80
*
* If the request has not entered async mode and the response is not yet
* committed we need to flush the response and close the outputstream.
*/
if (!servletRequest.isAsyncStarted() && !servletResponse.isCommitted()) {
servletResponse.flushBuffer();
try ( OutputStream outputStream = response.getWebApplicationOutputStream()) {
outputStream.flush();
}
request.setDispatcherType(dispatcherType);
}
}
@Override
public void include(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
WebApplicationRequest request = unwrap(servletRequest);
/* - JAVADOC, Servlet:SPEC:192
*
* Set dispatcher type to DispatcherType.INCLUDE.
*/
DispatcherType dispatcherType = request.getDispatcherType();
request.setDispatcherType(INCLUDE);
environment.getServlet().service(servletRequest, servletResponse);
request.setDispatcherType(dispatcherType);
}
/**
* Unwrap the servlet request.
*
* @param servletRequest the servlet request.
* @return the web application request.
*/
private WebApplicationRequest unwrap(ServletRequest servletRequest) {
ServletRequest currentRequest = servletRequest;
while (currentRequest instanceof ServletRequestWrapper wrapper) {
currentRequest = wrapper.getRequest();
}
return (WebApplicationRequest) currentRequest;
}
/**
* Unwrap the servlet response.
*
* @param servletResponse the servlet response.
* @return the web application response.
*/
private WebApplicationResponse unwrap(ServletResponse servletResponse) {
ServletResponse currentResponse = servletResponse;
while (currentResponse instanceof ServletResponseWrapper wrapper) {
currentResponse = wrapper.getResponse();
}
return (WebApplicationResponse) currentResponse;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultObjectInstanceManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.ObjectInstanceManager;
import jakarta.servlet.Filter;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import java.util.EventListener;
/**
* The default object instance manager.
*
*
* This object instance manager does not do any injection and that is by design.
* If you need injection into Servlets use the appropriate object instance
* manager for your injection framework.
*
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultObjectInstanceManager implements ObjectInstanceManager {
/**
* Constructor.
*/
public DefaultObjectInstanceManager() {
}
/**
* Create the filter.
*
* @param the return type.
* @param filterClass the filter class.
* @return the filter.
* @throws ServletException when it fails to create the filter.
*/
@Override
public T createFilter(Class filterClass) throws ServletException {
T result = null;
try {
result = filterClass.getDeclaredConstructor().newInstance();
} catch (Exception exception) {
throw new ServletException("Unable to create filter", exception);
}
return result;
}
/**
* Create the listener.
*
* @param the type.
* @param clazz the class of the listener to create.
* @return the listener.
* @throws ServletException when it fails to create the listener.
*/
@Override
public T createListener(Class clazz) throws ServletException {
T result;
try {
result = clazz.getDeclaredConstructor().newInstance();
} catch (Exception exception) {
throw new ServletException("Unable to create listener", exception);
}
return result;
}
/**
* Create the servlet.
*
* @param the return type.
* @param servletClass the servlet class.
* @return the servlet.
* @throws ServletException when it fails to create the servlet.
*/
@Override
public T createServlet(Class servletClass) throws ServletException {
T result;
try {
result = servletClass.getDeclaredConstructor().newInstance();
} catch (Exception exception) {
throw new ServletException("Unable to create servlet", exception);
}
return result;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultPiranha.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.Piranha;
import cloud.piranha.core.api.PiranhaConfiguration;
/**
* The default Piranha implementation.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultPiranha implements Piranha {
/**
* Stores the configuration.
*/
protected PiranhaConfiguration configuration;
/**
* Constructor.
*/
public DefaultPiranha() {
configuration = new DefaultPiranhaConfiguration();
}
@Override
public PiranhaConfiguration getConfiguration() {
return configuration;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultPiranhaBuilder.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.PiranhaBuilder;
import java.lang.System.Logger;
import static java.lang.System.Logger.Level.WARNING;
import java.lang.reflect.InvocationTargetException;
/**
* The default PiranhaBuilder.
*
* @author Manfred Riem (mriem@manorrock.com)
* @param the Piranha type.
*/
public class DefaultPiranhaBuilder implements PiranhaBuilder {
/**
* Stores the logger.
*/
private static final Logger LOGGER = System.getLogger(DefaultPiranhaBuilder.class.getName());
/**
* Stores the class type.
*/
private Class clazz;
/**
* Constructor.
*/
public DefaultPiranhaBuilder() {
}
@Override
public T build() {
try {
return (T) clazz.getDeclaredConstructor().newInstance();
} catch (NoSuchMethodException
| SecurityException
| InstantiationException
| IllegalAccessException
| IllegalArgumentException
| InvocationTargetException ex) {
LOGGER.log(WARNING, "Unable to create Pirana instance", ex);
return null;
}
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultPiranhaConfiguration.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.PiranhaConfiguration;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
/**
* The default Piranha configuration implementation.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultPiranhaConfiguration implements PiranhaConfiguration {
/**
* Stores the configuration.
*/
private final Map configuration = new HashMap<>();
/**
* Constructor
*/
public DefaultPiranhaConfiguration() {
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
if (configuration.containsKey(key)) {
return (boolean) configuration.get(key);
}
return defaultValue;
}
@Override
public Class> getClass(String key) {
return (Class>) configuration.get(key);
}
@Override
public File getFile(String key) {
return (File) configuration.get(key);
}
@Override
public Integer getInteger(String key) {
return (Integer) configuration.get(key);
}
@Override
public Long getLong(String key) {
return (Long) configuration.get(key);
}
@Override
public String getString(String key) {
return (String) configuration.get(key);
}
@Override
public void setBoolean(String key, Boolean value) {
configuration.put(key, value);
}
@Override
public void setClass(String key, Class> value) {
configuration.put(key, value);
}
@Override
public void setFile(String key, File value) {
configuration.put(key, value);
}
@Override
public void setInteger(String key, Integer value) {
configuration.put(key, value);
}
@Override
public void setLong(String key, Long value) {
configuration.put(key, value);
}
@Override
public void setString(String key, String value) {
configuration.put(key, value);
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultPushBuilder.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.WebApplicationRequest;
import jakarta.servlet.http.PushBuilder;
import java.util.HashSet;
import java.util.Set;
/**
* The default PushBuilder.
*
* @author Manfred Riem (mriem@manorrock.com)
*/
@SuppressWarnings("deprecation")
public class DefaultPushBuilder implements PushBuilder {
/**
* Stores the header manager.
*/
private final DefaultHttpHeaderManager headerManager = new DefaultHttpHeaderManager();
/**
* Stores the method.
*/
private String method;
/**
* Stores the path.
*/
private String path;
/**
* Stores the query string.
*/
private String queryString;
/**
* Stores the web application request.
*/
@SuppressWarnings("unused")
private final WebApplicationRequest request;
/**
* Stores the session id.
*/
private String sessionId;
/**
* Constructor.
*
* @param request the web application request.
*/
public DefaultPushBuilder(WebApplicationRequest request) {
this.request = request;
}
@Override
public PushBuilder method(String method) {
this.method = method;
return this;
}
@Override
public PushBuilder queryString(String queryString) {
this.queryString = queryString;
return this;
}
@Override
public PushBuilder sessionId(String sessionId) {
this.sessionId = sessionId;
return this;
}
@Override
public PushBuilder setHeader(String name, String value) {
headerManager.setHeader(name, value);
return this;
}
@Override
public PushBuilder addHeader(String name, String value) {
headerManager.addHeader(name, value);
return this;
}
@Override
public PushBuilder removeHeader(String name) {
headerManager.removeHeader(name);
return this;
}
@Override
public PushBuilder path(String path) {
this.path = path;
return this;
}
@Override
public void push() {
path = null;
}
@Override
public String getMethod() {
return method;
}
@Override
public String getQueryString() {
return queryString;
}
@Override
public String getSessionId() {
return sessionId;
}
@Override
public Set getHeaderNames() {
HashSet names = new HashSet<>();
headerManager.getHeaderNames()
.asIterator()
.forEachRemaining(name -> names.add(name));
return names;
}
@Override
public String getHeader(String name) {
return headerManager.getHeader(name);
}
@Override
public String getPath() {
return path;
}
}
================================================
FILE: core/impl/src/main/java/cloud/piranha/core/impl/DefaultSecurityManager.java
================================================
/*
* Copyright (c) 2002-2025 Manorrock.com. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package cloud.piranha.core.impl;
import cloud.piranha.core.api.SecurityConstraint;
import cloud.piranha.core.api.SecurityRoleReference;
import cloud.piranha.core.api.WebApplication;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* The default SecurityManager.
*
*
* This SecurityManager is securing nothing.
*
*
* @author Manfred Riem (mriem@manorrock.com)
*/
public class DefaultSecurityManager implements cloud.piranha.core.api.SecurityManager {
/**
* Stores the security constraints.
*/
private List securityConstraints;
/**
* Stores the security role references.
*/
private Map> securityRoleReferences;
/**
* Constructor.
*/
public DefaultSecurityManager() {
securityConstraints = new ArrayList<>();
securityRoleReferences = new HashMap<>();
}
@Override
public boolean authenticate(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
return false;
}
@Override
public void declareRoles(String[] roles) {
}
@Override
public Set getRoles() {
return Collections.emptySet();
}
@Override
public List getSecurityConstraints() {
return securityConstraints;
}
@Override
public Map> getSecurityRoleReferences() {
return securityRoleReferences;
}
@Override
public WebApplication getWebApplication() {
return null;
}
@Override
public boolean isUserInRole(HttpServletRequest request, String role) {
return false;
}
@Override
public void login(HttpServletRequest request, String username, String password) throws ServletException {
throw new ServletException("Unable to login");
}
@Override
public void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException {
}
@Override
public void setSecurityConstraints(List