Ubuntu 22.04 安装部署 Apache Lenya 指南
在 Ubuntu 22.04 上从零安装部署 Apache Lenya 2.0.4 的完整实录,涵盖依赖安装、源码下载校验、Ant 构建、内置 Jetty 与 Tomcat 9 两种启动方式、堆内存调整、排障与卸载。
Ubuntu 22.04 安装部署 Apache Lenya 指南
退役提示:Apache Lenya 已于 2015 年迁入 Apache Attic,终版 2.0.4(构建于 Cocoon 2.1)。本指南用于学习研究与遗产系统维护,不建议新项目采用。本文所有命令与回显均在 Ubuntu 22.04 服务器上真实执行并逐行核对。
一、部署形态与总体路线
Lenya 2.0.4 官方支持两种运行形态:其一为源码构建后使用自带的 Jetty 5.1.4 启动(./build.sh + ./lenya.sh,默认监听 8888 端口);其二为把构建产物 build/lenya/webapp 作为 ROOT 应用部署到外置 Tomcat。本文主线按"系统准备、依赖安装、下载校验、解压配置、构建、Jetty 启动验证、Tomcat 部署验证、卸载"展开,全部为真实执行的命令与真实回显。若目标只是快速体验,跳过第六章的 Tomcat 部分即可。
涉及软件版本如下(均为 Ubuntu 22.04 官方源可直接安装的版本):
| 组件 | 版本 | 说明 |
|---|---|---|
| Ubuntu | 22.04 LTS | 宿主操作系统 |
| OpenJDK | 1.8.0_504 | 构建与运行(官方声明 1.5/1.6,实测 8 可用) |
| Apache Ant | 1.10.12 | 系统源版本(Lenya 自带 Ant 1.7.1,构建实际使用自带版) |
| patch | 2.7.6 | 构建必需的工具 |
| unzip | 6.0 | 解压源码包 |
| Tomcat 9 | 9.0.58 | 可选外置 Servlet 环境 |
| curl | 7.81.0 | 验证 HTTP |
1.1 部署前环境预检
动手安装前建议先跑一组预检命令,确认 Java 可用、磁盘与内存余量足够、目标端口未被占用。实测环境执行结果如下:
java -version 2>&1 | head -1
df -h /opt | tail -1
free -m | head -2
(curl -s -o /dev/null -m 2 http://localhost:8888/ && echo "8888 已被占用") || echo "8888 可用"
实测回显:
openjdk version "1.8.0_504"
overlay 786G 488G 264G 65% /
Mem: 32050 20050 672 29 11327 11411
8888 可用
预检口径:Java 必须是 1.8 系(原因见 2.2);构建产物加源码树约占 1.5 GB,磁盘余量应留出数倍;运行期堆上限 512 MB 加上系统开销,2 GB 以上内存即可稳定运行;8888(Jetty)与 8080/8088(Tomcat,若走外置路线)任一被占用都需先处理,否则启动阶段才会暴露问题。另建议在预检阶段就完成下载包的 MD5 复核,实测对已下载的源码包再次执行 md5sum,结果 0e125533edaf35187c025bc01849f285 与官方值一致,可排除传输损坏。
二、系统准备与依赖安装
2.1 更新软件源并安装基础工具
以 root 或具备 sudo 权限的账号执行:
apt-get update
apt-get install -y openjdk-8-jdk ant patch unzip curl
实测回显(节选):
Setting up openjdk-8-jdk:amd64 (8u504-ga-1ubuntu1~22.04.3) ...
Setting up ant (1.10.12-1) ...
Processing triggers for man-db (2.10.2-1) ...
2.2 切换默认 Java 为 JDK 8
Ubuntu 22.04 的基础环境可能自带 OpenJDK 11,且默认 java 指向 11。Lenya 老代码在 JDK 11 下会出现模块系统相关异常(类加载被拒),因此统一固定到 JDK 8:
update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
update-alternatives --set javac /usr/lib/jvm/java-8-openjdk-amd64/bin/javac
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
java -version
实测回显:
update-alternatives: using /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java to provide /usr/bin/java (java) in manual mode
openjdk version "1.8.0_504"
OpenJDK Runtime Environment (build 1.8.0_504-ga-1ubuntu1~22.04.3)
OpenJDK 64-Bit Server VM (build 25.504-b00, mixed mode)
为使 JAVA_HOME 对后续会话持久生效,可写入 profile:
echo 'export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64' >> /etc/profile.d/java8.sh
这里展开说明 JDK 8 与更高版本冲突的机理,便于理解为什么必须显式固定。Lenya 依赖的 Cocoon 2.1 与其老版第三方库大量使用 javax.xxx 引导包名空间,Tomcat 在 JDK 11 下启动时,JDK 的模块封装会拒绝对这些内部 API 的反射访问;Jetty 5.1.4 更是早于模块系统十年,其类加载顺序依赖 -Djava.endorsed.dirs 这一在 JDK 9 之后已被移除的覆盖机制,实测 JDK 11 下类加载被直接拒绝。update-alternatives 是 Ubuntu 管理多版本命令符号链接的机制,--set 修改的是 /usr/bin/java 与 /usr/bin/javac 的指向;但 Tomcat 这类通过 systemd 启动的服务不读取交互 shell 的 PATH,必须像第七章那样在 /etc/default/tomcat9 单独指定 JAVA_HOME,两处口径不一致是老应用部署中最常见的隐蔽错误。
2.3 验证构建工具
ant -version
实测回显:
Apache Ant(TM) version 1.10.12 compiled on January 6 2022
注意:build.sh 实际会优先使用发行包内自带的 Ant 1.7.1(位于 tools/ 目录),系统 Ant 只是兜底,二者共存无冲突。
三、下载与校验
3.1 官方归档地址
项目退役后,官方唯一分发点为 Apache 归档服务器。源码包地址与官方 MD5 如下:
- 地址:https://archive.apache.org/dist/lenya/SOURCES/apache-lenya-2.0.4-src.zip
- 官方 MD5:0e125533edaf35187c025bc01849f285
3.2 下载并核对校验值
mkdir -p /opt/downloads && cd /opt/downloads
wget https://archive.apache.org/dist/lenya/SOURCES/apache-lenya-2.0.4-src.zip
wget https://archive.apache.org/dist/lenya/SOURCES/apache-lenya-2.0.4-src.zip.md5
md5sum -c apache-lenya-2.0.4-src.zip.md5
ls -la apache-lenya-2.0.4-src.zip
实测回显:
apache-lenya-2.0.4-src.zip: OK
-rw-r--r-- 1 root root 111581674 Oct 14 19:48 apache-lenya-2.0.4-src.zip
文件大小 111581674 字节(约 111 MB)。若网络受限导致 wget 速度过慢,可以为下载命令临时配置 HTTP 代理环境变量(http_proxy/https_proxy),不影响后续步骤。
关于校验方式有两点背景值得说明。其一,2000 年代的 Apache 发行惯用 MD5 而非 SHA256,本文按官方归档提供的方式核对 MD5;在能取得官方 MD5 文件的场景下,这足以发现下载损坏与传输截断,但它不能对抗蓄意篡改,安全要求高的环境应额外核对发布签名(归档目录同样提供了 .asc 签名文件,可用 gpg 验证)。其二,archive.apache.org 是面向归档流量的慢速站点,单线程下载百兆级文件常掉到百 KB 量级,实测多次重连可续传;wget 默认支持断点续传,中断后重跑同一条命令即可接着下,不必删除半成品文件。下载完成后立刻做 md5sum -c 再进入解压环节,能把问题截断在最早期。
3.3 解压
mkdir -p /opt/lenya-src && cd /opt/lenya-src
unzip -q /opt/downloads/apache-lenya-2.0.4-src.zip
ls /opt/lenya-src/apache-lenya-2.0.4-src
实测回显:
build.properties build.sh externals INSTALL-SRC.txt lenya.sh src tools
关键目录:src/(Lenya 本体源码)、externals/cocoon_2_1_x/(捆绑的 Cocoon 2.1 源码与预构建 Web 应用)、tools/(内置 Ant)、build.sh(构建)、lenya.sh(启动)。
四、构建前配置
4.1 阅读官方构建说明
先看 INSTALL-SRC.txt 的要点:需要 Ant、patch 工具;构建顺序是 configure(生成 local.build.properties)到 build 到 lenya.sh 启动;Tomcat 部署时需要在 JRE 的 endorsed 目录放置 xalan-2.7.1 与 xercesImpl-2.9.1。configure.sh 是交互式脚本,本文直接手工创建配置文件,效果等价且可控。
4.2 生成构建属性文件
cd /opt/lenya-src/apache-lenya-2.0.4-src
cp build.properties local.build.properties
cp src/cocoon/local.build.properties src/cocoon/local.blocks.properties externals/cocoon_2_1_x/
说明:源码包自带的 externals/cocoon_2_1_x/build/webapp 是预构建的 Cocoon 2.1.12-dev Web 应用,构建系统会用属性文件的版本号(local.build.properties 中的 revision 与 src/cocoon 目录的一致性)做同步校验,因此必须把 src/cocoon 下的两个属性文件复制到 externals/cocoon_2_1_x,否则构建第一步即失败并提示属性文件不同步。
local.build.properties 里有三组与运行形态直接相关的条目值得逐项理解,实测内容如下:
web.app.server=Jetty
web.app.server.jetty.port=8888
web.app.server.jetty.admin.port=8889
第一行决定 lenya.sh 的默认启动动作走 Jetty 路线(改为 Tomcat 时脚本行为随之变化);后两行分别注入 -Djetty.port 与 -Djetty.admin.port 系统属性,是 4.1 中 configure 交互脚本最终落盘的产物——本文手工创建属性文件,等价地拿到了同样的配置。构建属性文件还有一个隐性作用:它是版本一致性校验的锚点,任何一行被误改导致 revision 不匹配,构建都会在第一步报属性不同步错误。
4.3 赋予脚本执行权限
从 zip 解压出的脚本不带执行位,需手动补齐:
chmod +x build.sh lenya.sh configure.sh tools/bin/ant tools/bin/antRun
这条命令看似多余实则必做,原因在于 Linux 与 Windows 的文件权限语义差异:zip 归档虽然能保留 Unix 的可执行位,但经 Windows 中转或某些下载工具落盘后,解出的脚本往往丢失执行位,表现为 bash: ./build.sh: Permission denied。尤其容易漏掉的是 tools/bin/antRun 与 tools/bin/ant——前者是 Ant 的 exec 任务后端,后者是 Ant 启动器本体,二者缺一,构建都会在准备阶段报权限错误,报错信息却指向上层任务,容易被误判为脚本缺陷。执行位是文件级属性,与目录权限、SELinux/AppArmor 策略无关,遇到 Permission denied 时先核对 ls -l 输出中的 x 位即可快速定位。
五、构建
5.1 执行构建
cd /opt/lenya-src/apache-lenya-2.0.4-src
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
./build.sh
实测回显(节选):
Buildfile: build.xml
check-build-properties:
BUILD PROPERTIES OK
cocoon:
lenya-webapp:
Copying 35 files to /opt/lenya-src/apache-lenya-2.0.4-src/build/lenya/webapp/WEB-INF/lib
BUILD SUCCESSFUL
Total time: 3 seconds
构建产物位于 build/lenya/webapp,这是一个完整的 Servlet Web 应用(含 sitemap.xmap、lenya/ 出版站点目录、WEB-INF/lib 下 174 个 jar)。构建脚本自身以 -Xmx512M 运行 Ant,内存需求不高。实测在构建产物目录完全删除后重新全量构建,总耗时 10 秒;产物树顶层除 WEB-INF 外还包括 error.xmap、fallback-to-login.xmap、global-sitemap.xmap、jcr-repository、lenya.properties.xml 等入口文件,其中 jcr-repository 是仓库初始化的落地目录,首次启动时由它派生出出版站点的内容骨架。
5.2 首次构建常见失败与处理(真实排障实录)
排障一:属性文件不同步。若跳过 4.2 步直接构建,Ant 报错并中止:
BUILD FAILED
externals/cocoon_2_1_x/local.blocks.properties is NOT in sync with src/cocoon/local.blocks.properties
处理:按 4.2 复制两个属性文件后重新构建。
排障二:缺少 patch 工具。构建进入 Lenya 模块补丁阶段时报错:
apply-patches:
[echo] Applying patches to the Cocoon webapp
[exec] /bin/sh: 1: patch: not found
处理:执行 apt-get install -y patch,然后重新构建。这是官方 INSTALL-SRC.txt 明确列出的前置工具,容易被忽略。
六、启动方式一:内置 Jetty
6.1 调整 Java 堆内存
官方 lenya.sh 默认堆参数为 -Xms32M -Xmx512M,起始堆偏小。按生产规范将堆固定为 256 至 512 MB:编辑 lenya.sh 第 88 行,把
JAVA_OPTIONS='-Xms32M -Xmx512M -Djava.awt.headless=true'
改为
JAVA_OPTIONS='-Xms256M -Xmx512M -Djava.awt.headless=true'
6.2 处理 ICU4J 与新版 Java 的兼容问题
首次启动很可能遇到如下异常(真实堆栈节选):
java.lang.IllegalArgumentException: Invalid version number: Version number may be negative or greater than 255
at com.ibm.icu.util.VersionInfo.getInstance(VersionInfo.java:186)
at com.ibm.icu.impl.ICUDebug.getInstanceLenient(ICUDebug.java:113)
at com.ibm.icu.impl.ICUDebug.<clinit>(ICUDebug.java:59)
at org.apache.cocoon.components.deli.DeliImpl.initialize(DeliImpl.java:110)
原因:发行包内的 icu4j-2.8.jar 在初始化时会解析系统属性 java.version(1.8.0_504 的更新号 504 超过了 ICU 版本组件 0 至 255 的上限)。旧版 ICU 的类初始化一旦失败即抛出上述异常。处理方法:DELI(设备独立能力)组件在 Lenya 中并不被页面管线引用,可将其从 WEB-INF/cocoon.xconf 中注释掉。定位 cocoon.xconf 中形如下面的片段,加注释包裹:
<!-- <deli class="org.apache.cocoon.components.deli.DeliImpl">
(原 deli 配置内容保持不变)
</deli> -->
注意:每次重新构建都会重新生成 cocoon.xconf,需要在构建后重新执行该注释操作(可写成一条 sed 命令固化到部署脚本中)。
同一问题还有一条不依赖改 cocoon.xconf 的替代路线:在 JAVA_OPTIONS 中追加 -Djava.version=1.6,把 JDK 暴露给 ICU4J 的版本号伪装成 1.6,使其解析逻辑不再越界。实测最终生效的第 88 行为:
JAVA_OPTIONS='-Xms256M -Xmx512M -Djava.awt.headless=true -Djava.version=1.6'
两种手段可以叠加使用(实测环境即是如此),也可以只取其一;若选择注释 deli 路线,建议同时保留该参数,因为老版 ICU4J 的版本解析点不止 DELI 一处,多一道保险的代价仅是一个启动参数。
顺带展开两个堆参数的含义与调整依据。-Xms 是初始堆大小,-Xmx 是上限,JVM 在运行中于两者之间伸缩;发行脚本默认的 -Xms32M 意味着进程起步只拿 32 MB 堆,而 Cocoon 初始化时就要装配数百个组件、预编译若干 XSLT,实测启动期短时分配压力直接逼近初始堆的数倍,因此把 -Xms 提到 256 M 让堆一次到位,避免启动初期反复触发堆扩张与随之而来的垃圾回收停顿。-Xmx512M 对单出版站点的演示负载绰绰有余,若站点内容量大或并行编辑用户多,可上调至 1G 级别;再高则意义有限,因为 Lenya 的性能瓶颈更多在 XSLT 转换而非内存容量。改 JAVA_OPTIONS 后需 kill 进程重启生效,验证方式即第六章的 ps 命令行复查。
6.3 启动并验证
cd /opt/lenya-src/apache-lenya-2.0.4-src
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
nohup ./lenya.sh > /tmp/lenya-run.log 2>&1 &
等待约 30 至 45 秒(Jetty 初始化 Cocoon),然后验证:
curl -s -D- -o /dev/null http://localhost:8888/
curl -s http://localhost:8888/ | grep -oiE '<title>[^<]*'
实测回显:
HTTP/1.1 302 Found
Server: Jetty/5.1.4 (Linux/6.8.0-138-generic amd64 java/1.8.0_504
X-Cocoon-Version: 2.1.12-dev
Apache Lenya - Content Management System
6.4 确认堆内存
ps -ef | grep [j]ava
实测回显:
root 2177 1 1 20:04 ? 00:00:02 /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
-Xms256M -Xmx512M -Djava.awt.headless=true -cp /opt/lenya-src/apache-lenya-2.0.4-src/build/lenya/tools/jetty/start.jar
org.mortbay.loader.Main
可见进程堆参数为 -Xms256M -Xmx512M,符合 256 至 512 MB 的规范区间。
6.5 停止
kill $(pgrep -f org.mortbay)
Jetty 以前台进程方式运行在 nohup 下,直接向进程发送 SIGTERM 即可优雅关闭。
6.6 启动日志与日志文件布局
启动脚本的 stdout 分两部分:先是脚本自身的 INFO 行,实测依次打印 "INFO: Jetty Port is 8888" 与 "INFO: Jetty Admin Port is 8889"(后者为预留管理端口,默认不启用监听器,探测 8889 会得到连接拒绝,属预期现象);随后是 Jetty 与 Cocoon 的初始化日志,实测特征行包括:
0 [main] INFO org.mortbay.util.Credential - Checking Resource aliases
134 [main] INFO org.mortbay.http.HttpServer - Version Jetty/5.1.4
393 [main] INFO org.mortbay.util.Container - Started org.mortbay.jetty.servlet.WebApplicationHandler
服务稳定运行后,运行期日志集中在 build/lenya/webapp/WEB-INF/logs/ 目录,实测包含五个文件:log4j.log(Cocoon 与 Lenya 应用主日志,排障首选)、jetty-log4j.log(Jetty 服务层日志)、sessions.log(会话建立与销毁)、repository.log(仓库操作日志,checkout/checkin 等动作留痕于此)、2026_10_14.request.log(按天滚动的访问日志,文件名含日期)。分层放置的好处是排障时可以按问题类型直达:页面渲染异常看 log4j.log,锁与保存问题看 repository.log 加 log4j.log 中的 lockInvolvedObjects 行,登录异常对照 sessions.log。巡检时应把该目录纳入定期备份范围,它与内容目录一起构成完整的运行证据链。
七、启动方式二:外置 Tomcat 9
7.1 安装 Tomcat 9 并配置堆内存
apt-get install -y tomcat9
printf 'JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64\nJAVA_OPTS="-Djava.awt.headless=true -Xms256M -Xmx512M"\n' > /etc/default/tomcat9
systemctl restart tomcat9
说明:Ubuntu 22.04 的 tomcat9 包默认使用系统 default-java(OpenJDK 11),而 Lenya 老代码在 JDK 11 下初始化失败(日志出现 ClassCastException 与模块访问异常),因此必须在 /etc/default/tomcat9 显式指定 JAVA_HOME 为 JDK 8,并同步写入堆参数。
7.2 放置 endorsed 库
Cocoon 2.1 需要 XML 解析器与转换器的优先版本。把它们放入 JDK 8 的 endorsed 目录:
mkdir -p /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/endorsed
cd /opt/lenya-src/apache-lenya-2.0.4-src/externals/cocoon_2_1_x/lib/endorsed
cp xalan-2.7.1.jar xercesImpl-2.9.1.jar xml-apis-1.3.04.jar /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/endorsed/
7.3 以 ROOT 应用部署构建产物
Lenya 构建产物本身是 ROOT 形态的 Web 应用(站点 sitemap 在根路径),直接覆盖部署:
systemctl stop tomcat9
rm -rf /var/lib/tomcat9/webapps/ROOT
cp -r /opt/lenya-src/apache-lenya-2.0.4-src/build/lenya/webapp /var/lib/tomcat9/webapps/ROOT
chown -R tomcat:tomcat /var/lib/tomcat9/webapps/ROOT
systemctl start tomcat9
7.4 处理 WEB-INF/lib/endorsed 子目录
首次访问会遇到 500,Tomcat 日志(/var/log/tomcat9/localhost.日期.log)出现:
java.lang.NoClassDefFoundError: org/apache/regexp/RESyntaxException
Caused by: java.lang.ClassNotFoundException: org.apache.regexp.RESyntaxException
原因:发行包把 jakarta-regexp-1.5.jar 等五个 jar 放在 WEB-INF/lib/endorsed 子目录,Jetty 的启动脚本会把它加入类路径,而 Tomcat 只扫描 WEB-INF/lib 顶层的 jar。处理:上移一层并重启:
cp /var/lib/tomcat9/webapps/ROOT/WEB-INF/lib/endorsed/*.jar /var/lib/tomcat9/webapps/ROOT/WEB-INF/lib/
chown tomcat:tomcat /var/lib/tomcat9/webapps/ROOT/WEB-INF/lib/*.jar
systemctl restart tomcat9
7.5 验证
curl -s -o /dev/null -w 'TOMCAT=%{http_code}\n' http://localhost:8088/
curl -s http://localhost:8088/ | grep -oiE '<title>[^<]*'
实测回显(Tomcat 连接器端口已在 server.xml 中改为 8088,避免与 Jetty 8888 冲突;保持 8080 亦可):
TOMCAT=200
Apache Lenya - Content Management System
再验证发布区页面与堆参数:
curl -s -o /dev/null -w 'LIVE=%{http_code}\n' http://localhost:8088/default/live/index.html
ps -ef | grep [j]ava
实测回显:
LIVE=200
tomcat 14296 1 12 20:41 ? 00:00:05 /usr/lib/jvm/java-8-openjdk-amd64//bin/java
-Djava.util.logging.config.file=/var/lib/tomcat9/conf/logging.properties -Djava.awt.headless=true
-Xms256M -Xmx512M -Dcatalina.base=/var/lib/tomcat9 org.apache.catalina.startup.Bootstrap start
至此两种运行形态均部署完成。初始化数据库与示例内容的导入、登录、建页、发布等操作见本专栏实战篇。
在 Jetty 与 Tomcat 两条路线之间的选择,可以归结为部署目标与运行特征的三点差异。一是定位:内置 Jetty 是开发与演示形态,随构建产物开箱即跑、进程管理简单,但单点单应用;外置 Tomcat 是生产形态,与系统服务管理(systemd)、日志轮转(logrotate)、多应用共存等基础设施自然衔接。二是生命周期:Jetty 进程完全由 lenya.sh 与 nohup 控制,重启即杀进程再拉起,Tomcat 则由 systemctl 统一管理,开机自启与崩溃恢复开箱即得。三是修复面:外置 Tomcat 路线多出"构建产物复制"与"endorsed 库上移"两个动作,且其代码复制进 webapps 后与构建产物脱钩,再次构建时必须重新同步;Jetty 路线直接运行 build/lenya/webapp,代码即产物,不存在同步漂移问题。同一份构建产物在两条路线上均通过了登录、创建与发布的全流程实测,功能面没有差异。
远程访问与网络放行是部署收尾的必答题。Ubuntu 22.04 默认启用 ufw,如需放行对应端口执行 ufw allow 8888(Jetty 路线)或 ufw allow 8088(Tomcat 路线);云环境还要同步检查安全组规则。绑定地址方面,Jetty 5.1.4 的默认监听器绑定全部网卡,Tomcat 9 的 Connector 同样默认 0.0.0.0,老版本应用没有现代 Web 框架常见的本机绑定或鉴权兜底,这意味着部署完成那一刻服务就对全网段可达,而 Lenya 的管理面(编辑区)与公开面(live 区)共用同一端口,仅靠登录与 ACML 策略区分。因此在遗产系统上更稳妥的收尾是:要么以防火墙限制来源网段,要么在 Tomcat 侧增加 RemoteAddrValve 做第二层来源过滤,切忌把 8888/8088 直接暴露在公网。
八、历史二进制版 1.2.5 的说明
归档目录 BINARIES 下提供 apache-lenya-1.2.5-bin.tar.gz(约 31 MB),实测解压后的顶层结构为:
CREDITS.txt INSTALL-BIN.txt LICENSE.txt NOTICE.txt README.txt
legal lenya.bat lenya.sh lenya.war tools
与 2.0.4 源码发行相比,1.2.5 二进制版没有 src 与 externals 目录,核心就是一个可直接部署的 lenya.war,面向 2005 年前后的 Tomcat 4/5 环境。由于本文实测环境已将 2.0.4 源码构建完整跑通(Jetty 与 Tomcat 9 双通道),无需回退到 1.2.5。若确需体验 1.2.5,将其 lenya.war 放入老版 Tomcat 的 webapps 目录即可,其 INSTALL-BIN.txt 有逐步说明;在 Tomcat 9 上运行 1.2.5 的 war 未经验证,不建议尝试。两条产品线的取舍也有参考价值:1.2 系部署简单但功能停留在单出版站点形态,2.0 系引入 Publication、新工作流与新访问控制体系但依赖链陡增——这种"老线简单、新线复杂"的断层,正是理解 Lenya 社区后期维护成本的一个窗口。
九、卸载
9.1 停止服务
kill $(pgrep -f org.mortbay)
systemctl stop tomcat9
ps -ef | grep [j]ava
实测确认所有 Java 进程退出(grep 无输出)。
9.2 删除应用与构建目录
rm -rf /opt/lenya-src/apache-lenya-2.0.4-src/build /var/lib/tomcat9/webapps/ROOT
rm -f /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/endorsed/*.jar
9.3 卸载软件包
apt-get purge -y tomcat9 tomcat9-common ant
apt-get autoremove -y
apt-get purge -y openjdk-8-jdk
卸载顺序上有一个纪律性要求:先停进程再删文件,可以避免运行中的 Java 进程持有日志与内容目录的句柄导致删除瞬间残留;而 content/ 与 config/ 两目录一旦随构建产物被删且无备份,站点状态不可恢复——2.0 系"代码即产物"的目录形态让卸载与删除站点数据之间只隔一个 rm -rf,操作前务必确认备份在别处。
实测卸载后验证:
which ant
ls /var/lib/tomcat9
java -version
回显依次为空、ls 报 cannot access 与 bash: java: command not found,说明环境已完全清理。如需保留 JDK 8 给其他应用使用,跳过最后一条卸载命令即可。
十、部署完成后的验证清单
部署完成不等于验证完成,建议按下面的顺序逐项确认,任何一项不过关都应回到对应章节排查:
- 进程与堆:
ps -ef | grep [j]ava命令行包含 -Xms256M -Xmx512M(Jetty 路线看 JAVA_OPTIONS,Tomcat 路线看 JAVA_OPTS); - 端口与响应:curl 首页返回 302 并跳转登录页,响应头含 Server: Jetty/5.1.4 与 X-Cocoon-Version: 2.1.12-dev;
- 日志静默:WEB-INF/logs/log4j.log 中无 ERROR 级新条目(DELI 未注释时的 ICU4J 异常、缺 endorsed 库时的 NoClassDefFoundError 都会在这里最先暴露);
- 登录链路:以默认账号登录编辑区成功,出现 Getting Started 向导或站点菜单;
- 内容目录:导入示例内容后 content/authoring 下出现 UUID 目录与 sitetree.xml;
- 权限闭环:编辑区内能看到 bxe.edit/kupu.edit/workflow.publish 等用例菜单项,说明用例级策略装配正常;
- 备份锚点:确认 content/ 与 config/ 两个目录的位置并纳入备份计划,二者即站点全部状态。
这套清单与第六、七章的验证命令一一对应,可作为版本迁移或参数调整后的回归检查单使用。
十一、常见问题解答(FAQ)
Q1:构建报 local.blocks.properties is NOT in sync 怎么办? 把 src/cocoon 下的 local.build.properties 与 local.blocks.properties 复制到 externals/cocoon_2_1_x 目录再构建。这是源码包自带的预构建 Cocoon webapp 的版本一致性校验,属于必做步骤(见 4.2 与排障实录)。
Q2:构建中途报 patch: not found? 安装 patch:apt-get install -y patch。Lenya 构建需要用 patch 工具向 Cocoon webapp 应用模块补丁,官方安装说明列为前置条件,实测缺少它构建必失败。
Q3:启动即抛 Invalid version number: Version number may be negative or greater than 255? 这是 icu4j-2.8 解析 java.version(如 1.8.0_504)失败导致,触发链路是 Cocoon 的 DELI 组件初始化。在 WEB-INF/cocoon.xconf 中注释掉 deli 组件定义即可。注意重新构建会覆盖该文件,需要重新处理。
Q4:访问 8888 端口一直是 404? 多为服务尚未初始化完成(Cocoon 首次装配约需 30 至 45 秒),或浏览器访问了 /lenya/default/authoring 这类错误路径。Lenya 2.0.4 的 URL 形态是 /default/authoring/(出版站点挂在根路径下),首页为 http://服务器地址:8888/。
Q5:Tomcat 部署后 500,日志报 NoClassDefFoundError: org/apache/regexp/RESyntaxException? 把 WEB-INF/lib/endorsed 子目录里的 jar 全部上移到 WEB-INF/lib 顶层并重启 Tomcat。Tomcat 不扫描 lib 的子目录,Jetty 则会扫描,这是两种 Servlet 环境的差异点(见 7.4)。
Q6:Tomcat 启动后日志出现 ClassCastException(ObjectStreamClass$Caches$1 cannot be cast to java.util.Map)? Tomcat 正跑在 OpenJDK 11 上。在 /etc/default/tomcat9 写入 JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 后 systemctl restart tomcat9。Lenya 2.0.4 依赖 JDK 8 时代的序列化行为。
Q7:Java 进程堆内存应如何设置与确认? Jetty 方式修改 lenya.sh 的 JAVA_OPTIONS 为 -Xms256M -Xmx512M;Tomcat 方式修改 /etc/default/tomcat9 的 JAVA_OPTS。两种方式均以 ps -ef | grep [j]ava 确认命令行中包含该参数(本文 6.4 与 7.5 有真实回显)。
Q8:默认管理账号是什么? 默认出版站点有两个账号:lenya(属于 admin、editor、sitemanager 组)与 alice(属于 editor 组)。口令散列为 MD5,存储在 lenya/pubs/default/config/access-control/passwd 下的 .iml 文件中。首次部署应立即修改:用 md5sum 生成新口令散列,替换 .iml 中 password 字段的值后重启。修改后用 admin 组外的 reviewer 组配合才能完成发布工作流(角色模型见实战篇)。
Q9:如何更改监听端口? Jetty 方式:lenya.sh 中 Jetty 的配置由 build/lenya/tools/jetty/etc/jetty.xml 控制,修改其中的 8888 端口后重启;Tomcat 方式:编辑 /var/lib/tomcat9/conf/server.xml 中 Connector 的 port 属性。实测将 Tomcat 改为 8088 与 Jetty 8888 并行运行互不影响。
Q10:可以完全不联网安装吗? 不行。源码包虽内嵌 Cocoon 与全部依赖 jar(构建期不需要访问任何远程仓库,实测全程离线构建成功),但下载源码包本身需要网络。预先在有网环境下载 apache-lenya-2.0.4-src.zip 与 md5 文件,再拷贝到目标服务器即可完成后续全部离线步骤。
Q11:启动日志打印 Jetty Admin Port is 8889,为什么探测 8889 连接被拒绝? 8889 是预留的管理监听器端口,其配置在 tools/jetty/conf/admin.xml,默认启动只装配 main.xml,管理监听器并未启用,连接拒绝属预期。确实需要时要把 admin.xml 加入启动配置,否则不要把 8889 纳入服务暴露面清单。
Q12:JAVA_OPTIONS 里的 -Djava.version=1.6 是什么作用,能去掉吗? 它把系统属性 java.version 伪装为 1.6,规避老版 ICU4J 解析 "1.8.0_504" 时更新号超过 255 引发的初始化异常,与注释 DELI 组件是同一问题的两条路线。实测环境两者叠加运行稳定;若部署环境的 JDK 更新号不超过 255(如 8u191),理论上可去掉,但保留的成本可以忽略,建议不动。
Q13:全量构建与增量构建的耗时差异有多大? 实测构建产物目录存在时构建约 3 秒,产物目录完全删除后的全量构建约 10 秒,差异主要来自 Cocoon webapp 的复制与模块补丁重放。无论哪种规模,构建都不是部署的耗时瓶颈,瓶颈在首次下载 111 MB 源码包。
十二、参考链接
- Apache Attic 项目页(退役信息与归档入口):https://attic.apache.org/projects/lenya.html
- Lenya 源码与校验文件归档:https://archive.apache.org/dist/lenya/SOURCES/
- Lenya 历史二进制归档:https://archive.apache.org/dist/lenya/BINARIES/
- Lenya INSTALL-SRC.txt(构建说明,包内文档):https://archive.apache.org/dist/lenya/SOURCES/apache-lenya-2.0.4-src.zip
- Ubuntu 22.04 仓库 OpenJDK 8 说明:https://packages.ubuntu.com/jammy/openjdk-8-jdk
- Tomcat 9 官方文档:https://tomcat.apache.org/tomcat-9.0-doc/
- Apache Cocoon 2.1 文档:https://cocoon.apache.org/2.1/
- Xerces-J 2.9.1 与 Xalan 2.7.1(endorsed 机制背景):https://xerces.apache.org/xerces-j/