The classic O'Reilly COS (com.oreilly.servlet) utility library — file upload, HTTP messaging and servlet helpers — maintained for the Jakarta EE Servlet API.
- 1. Project Overview
- 2. Features & Status
- 3. Requirements & Compatibility
- 4. Architecture & Modules
- 5. Installation
- 6. Quick Start
- 7. Configuration
- 8. Core Usage / API
- 9. Testing & Build
- 10. Versioning & Branches
- 11. Contributing & License
cos is a maintained fork of the classic O'Reilly COS library
(com.oreilly.servlet), modernized for the Jakarta EE Servlet API. It provides
battle-tested server-side web utilities:
- File upload —
MultipartRequest("push" model: files are saved to disk while parsing themultipart/form-datarequest) andMultipartParser("pull" model), with pluggableFileRenamePolicy, configurable size limits and encodings. - HTTP messaging —
HttpMessage/HttpsMessagefor GET / POST requests with headers and properties,MailMessagefor sending email. - Servlet helpers —
CookieParser,ParameterParser,ServletUtils,HttpUtils,Base64Encoder/Base64Decoder,LocaleNegotiator,CacheHttpServlet/DaemonHttpServlet/RemoteHttpServletbase classes.
What it is not:
- Not a framework or a servlet container — it runs inside any Servlet container.
- Not an actively extended API surface — the code base deliberately keeps the classic, stable COS interfaces.
Typical scenarios:
| Scenario | What you use |
|---|---|
Handle multipart/form-data upload in a servlet |
MultipartRequest (push) / MultipartParser (pull) |
| Rename / relocate uploaded files | FileRenamePolicy, DefaultFileRenamePolicy |
| Send HTTP GET / POST from the server | HttpMessage, HttpsMessage |
| Read cookies / parameters safely | CookieParser, ParameterParser |
| Send plain email | MailMessage |
| Capability | Status | Notes |
|---|---|---|
MultipartRequest (push upload) |
Stable | Saves files to disk during construction; getFile, getParameter, getContentType, getFilesystemName, getOriginalFileName |
MultipartParser (pull upload) |
Stable | Streaming part parsing; FilePart, ParamPart, Part |
| File rename policies | Stable | FileRenamePolicy, DefaultFileRenamePolicy, ExceededSizeException |
| HTTP client helpers | Stable | HttpMessage, HttpsMessage (sendGetMessage, sendPostMessage) |
| Email helper | Stable | MailMessage |
| Servlet utilities | Stable | ServletUtils, HttpUtils, CookieParser, ParameterParser, Base64Encoder / Base64Decoder, LocaleNegotiator |
| Base servlet classes | Stable | CacheHttpServlet, DaemonHttpServlet, RemoteHttpServlet, MultipartFilter, MultipartWrapper |
| Requirement | Version / Notes |
|---|---|
| JDK | 17+ (see version matrix below) |
| Maven | 3.0+ (enforced) |
| Servlet API | Jakarta EE 9+ (jakarta.servlet-api, provided scope — supplied by your container) |
Version lines (this project follows the upstream COS version line 6.0.x.*):
| Branch | JDK | Version |
|---|---|---|
feature/1.0.x |
11 | 6.0.x.* |
feature/2.0.x |
17 | 6.0.x.* |
feature/3.0.x |
21 | 6.0.x.* |
Unlike the other easy4j components,
coskeeps the upstream-aligned6.0.x.*version line on every branch (verified in the branch poms); only the JDK baseline differs per branch.
+---------------------+ +--------------------------------------+
| HTTP request | | cos (com.oreilly.servlet) |
| (multipart/form- |-->| upload : MultipartRequest, |
| data, query params)| | MultipartParser, FilePart |
| | | http : HttpMessage, HttpsMessage |
| Servlet container | | servlet: CookieParser, ServletUtils,|
| (jakarta.servlet) |-->| Base64Encoder/Decoder, |
| | | CacheHttpServlet ... |
+---------------------+ +-------------------+------------------+
|
v
+-------------------------------------------+
| Files saved / response to client |
+-------------------------------------------+
Single-module Maven project (packaging: jar, plus a minimal src/main/webapp
web descriptor). No child modules.
| Artifact | Responsibility |
|---|---|
io.github.easy4j:cos |
File upload, HTTP messaging and servlet utility classes |
Key packages:
| Package | Content |
|---|---|
com.oreilly.servlet |
MultipartRequest, HttpMessage, HttpsMessage, MailMessage, ServletUtils, HttpUtils, CookieParser, Base64Encoder / Base64Decoder, servlet base classes |
com.oreilly.servlet.multipart |
MultipartParser, FilePart, ParamPart, Part, FileRenamePolicy, DefaultFileRenamePolicy, ExceededSizeException |
The project is not yet published to Maven Central. Snapshots/releases are distributed through the Aliyun Maven repository and GitHub Releases.
Maven:
<dependency>
<groupId>io.github.easy4j</groupId>
<artifactId>cos</artifactId>
<version>6.0.x.20241003.RELEASE</version>
</dependency>Gradle:
implementation 'io.github.easy4j:cos:6.0.x.20241003.RELEASE'Handle a file upload in a servlet:
import com.oreilly.servlet.MultipartRequest;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
public class UploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// parse multipart/form-data, saving uploaded files to /tmp/upload
MultipartRequest multi = new MultipartRequest(request, "/tmp/upload");
String name = multi.getParameter("name"); // ordinary form field
File uploaded = multi.getFile("file"); // uploaded file (or null)
String fileName = multi.getFilesystemName("file");
String originalName = multi.getOriginalFileName("file");
response.getWriter().write("saved=" + fileName + " (original: " + originalName + ")");
}
}Expected result: the uploaded file is written under /tmp/upload (renamed by the
default policy if a collision occurs), and the servlet reports the saved file name.
The library has no configuration file or property prefix. Behaviour is controlled per call through the constructors:
| Constructor / method | Description |
|---|---|
MultipartRequest(request, saveDirectory) |
Default: max post size 1 MB, default encoding |
MultipartRequest(request, saveDirectory, maxPostSize) |
Raise the 1 MB default limit |
MultipartRequest(request, saveDirectory, maxPostSize, encoding) |
Internationalized file names |
MultipartRequest(request, saveDirectory, maxPostSize, encoding, FileRenamePolicy) |
Custom rename / relocation policy |
MultipartParser(request, maxPostSize) |
Pull model: iterate Part objects (FilePart, ParamPart) |
Use the pull model when you want full control (e.g. write files to a database):
import com.oreilly.servlet.multipart.*;
MultipartParser parser = new MultipartParser(request, 10 * 1024 * 1024);
Part part;
while ((part = parser.readNextPart()) != null) {
if (part.isParam()) {
ParamPart param = (ParamPart) part;
System.out.println(param.getName() + " = " + param.getStringValue());
} else if (part.isFile()) {
FilePart filePart = (FilePart) part;
filePart.writeTo(new java.io.FileOutputStream("/tmp/" + filePart.getFileName()));
}
}import com.oreilly.servlet.HttpMessage;
import java.net.URL;
import java.io.InputStream;
HttpMessage msg = new HttpMessage(new URL("https://example.com/api"));
msg.setHeader("Authorization", "Bearer token");
InputStream in = msg.sendPostMessage(); // or sendGetMessage()mvn clean verify- The build is configured with the JaCoCo Maven plugin (report +
checkgoal with a 90% line-coverage rule bound to theverifyphase;haltOnFailure=false). - Assumption: the 1.0.x branch currently checks in no test sources under
src/test; coverage thresholds are therefore enforced only when tests exist. - No CI workflow files are present under
.github/in this worktree. - Note: this worktree has no Maven Wrapper; use a local Maven 3.x installation.
| Branch | JDK | Version | Notes |
|---|---|---|---|
feature/1.0.x |
11 | 6.0.x.* |
Current branch, maintained |
feature/2.0.x |
17 | 6.0.x.* |
JDK 17 line |
feature/3.0.x |
21 | 6.0.x.* |
JDK 21 line |
This component keeps the upstream COS version line (6.0.x.*) instead of the
1.0.x.* / 2.0.x.* / 3.0.x.* scheme used by the other easy4j components; the
JDK baseline is the only thing that changes per branch. Releases are published to
the Aliyun Maven repository and as GitHub Releases; the project is not yet
published to Maven Central.
Contributions are welcome — please open issues or pull requests on GitHub.
Licensed under the Apache License, Version 2.0.