添加kkfile
This commit is contained in:
commit
c720d2ed1e
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
*.css linguist-language=java
|
||||||
|
*.less linguist-language=java
|
||||||
|
*.js linguist-language=java
|
||||||
|
*.html linguist-language=java
|
||||||
|
*.* linguist-language=java
|
41
Dockerfile.bak
Normal file
41
Dockerfile.bak
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
FROM ubuntu:20.04
|
||||||
|
MAINTAINER chenjh "842761733@qq.com"
|
||||||
|
ADD server/target/kkFileView-*.tar.gz /opt/
|
||||||
|
COPY fonts/* /usr/share/fonts/chinese/
|
||||||
|
RUN echo "deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse" > /etc/apt/sources.list &&\
|
||||||
|
apt-get clean && apt-get update &&\
|
||||||
|
apt-get install -y locales && apt-get install -y language-pack-zh-hans &&\
|
||||||
|
localedef -i zh_CN -c -f UTF-8 -A /usr/share/locale/locale.alias zh_CN.UTF-8 && locale-gen zh_CN.UTF-8 &&\
|
||||||
|
apt-get install -y tzdata && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&\
|
||||||
|
apt-get install -y libxrender1 && apt-get install -y libxt6 && apt-get install -y libxext-dev && apt-get install -y libfreetype6-dev &&\
|
||||||
|
apt-get install -y wget && apt-get install -y ttf-mscorefonts-installer && apt-get install -y fontconfig &&\
|
||||||
|
apt-get install ttf-wqy-microhei &&\
|
||||||
|
apt-get install ttf-wqy-zenhei &&\
|
||||||
|
apt-get install xfonts-wqy &&\
|
||||||
|
cd /tmp &&\
|
||||||
|
wget https://kkfileview.keking.cn/server-jre-8u251-linux-x64.tar.gz &&\
|
||||||
|
tar -zxf /tmp/server-jre-8u251-linux-x64.tar.gz && mv /tmp/jdk1.8.0_251 /usr/local/ &&\
|
||||||
|
|
||||||
|
# 安装 OpenOffice
|
||||||
|
# wget https://kkfileview.keking.cn/Apache_OpenOffice_4.1.6_Linux_x86-64_install-deb_zh-CN.tar.gz -cO openoffice_deb.tar.gz &&\
|
||||||
|
# tar -zxf /tmp/openoffice_deb.tar.gz && cd /tmp/zh-CN/DEBS &&\
|
||||||
|
# dpkg -i *.deb && dpkg -i desktop-integration/openoffice4.1-debian-menus_4.1.6-9790_all.deb &&\
|
||||||
|
|
||||||
|
# 安装 libreoffice
|
||||||
|
apt-get install -y libxinerama1 libcairo2 libcups2 libx11-xcb1 &&\
|
||||||
|
wget https://kkfileview.keking.cn/LibreOffice_7.1.4_Linux_x86-64_deb.tar.gz -cO libreoffice_deb.tar.gz &&\
|
||||||
|
tar -zxf /tmp/libreoffice_deb.tar.gz && cd /tmp/LibreOffice_7.1.4.2_Linux_x86-64_deb/DEBS &&\
|
||||||
|
dpkg -i *.deb &&\
|
||||||
|
|
||||||
|
rm -rf /tmp/* && rm -rf /var/lib/apt/lists/* &&\
|
||||||
|
cd /usr/share/fonts/chinese &&\
|
||||||
|
mkfontscale &&\
|
||||||
|
mkfontdir &&\
|
||||||
|
fc-cache -fv
|
||||||
|
ENV JAVA_HOME /usr/local/jdk1.8.0_251
|
||||||
|
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
|
||||||
|
ENV PATH $PATH:$JAVA_HOME/bin
|
||||||
|
ENV LANG zh_CN.UTF-8
|
||||||
|
ENV LC_ALL zh_CN.UTF-8
|
||||||
|
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-4.0.0/bin
|
||||||
|
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dspring.config.location=/opt/kkFileView-4.0.0/config/application.properties","-jar","/opt/kkFileView-4.0.0/bin/kkFileView-4.0.0.jar"]
|
14
Dockerfile.crm-print
Normal file
14
Dockerfile.crm-print
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM openjdk:8u181-jre-alpine
|
||||||
|
|
||||||
|
ENV TIME_ZONE=Asia/Shanghai
|
||||||
|
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/' /etc/apk/repositories
|
||||||
|
RUN apk add --update font-adobe-100dpi ttf-dejavu fontconfig
|
||||||
|
RUN apk update && apk add --no-cache tzdata curl\
|
||||||
|
&& echo "${TIME_ZONE}" > /etc/timezone \
|
||||||
|
&& ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime
|
||||||
|
COPY ./server/target/crm-print-server-1.0.0.jar /
|
||||||
|
RUN mkdir /templates
|
||||||
|
WORKDIR /
|
||||||
|
HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost:9089/crm-print/actuator/health || exit 1
|
||||||
|
EXPOSE 9089
|
||||||
|
CMD ["java","-Xms1000m","-Xmx1000m","-jar","crm-print-server-1.0.0.jar"]
|
26
Dockerfile_gray
Normal file
26
Dockerfile_gray
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
FROM openjdk:8u181-jre-alpine
|
||||||
|
ENV LANG en_US.UTF-8
|
||||||
|
RUN set -eux && sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories &&\
|
||||||
|
apk add tzdata &&\
|
||||||
|
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone &&\
|
||||||
|
apk add --no-cache curl font-adobe-100dpi ttf-dejavu fontconfig &&\
|
||||||
|
apk add libreoffice &&\
|
||||||
|
apk add wget &&\
|
||||||
|
apk add libc6-compat &&\
|
||||||
|
apk add msttcorefonts-installer &&\
|
||||||
|
apk add fontconfig &&\
|
||||||
|
apk --update add unzip &&\
|
||||||
|
mkdir -p /usr/share/fonts/chinese &&\
|
||||||
|
cd /tmp &&\
|
||||||
|
wget http://kkfileview.keking.cn/fonts.zip &&\
|
||||||
|
unzip -d /usr/share/fonts/chinese fonts.zip &&\
|
||||||
|
cd /usr/share/fonts/chinese &&\
|
||||||
|
mkfontscale &&\
|
||||||
|
mkfontdir &&\
|
||||||
|
fc-cache -fv &&\
|
||||||
|
rm -rf /var/cache/*
|
||||||
|
|
||||||
|
COPY ./server/target/crm-print-server-1.0.0.jar /
|
||||||
|
WORKDIR /
|
||||||
|
EXPOSE 9089
|
||||||
|
CMD ["java","-Xms1000m","-Xmx1000m","-jar","crm-print-server-1.0.0.jar"]
|
26
Dockerfile_test
Normal file
26
Dockerfile_test
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
FROM openjdk:8u181-jre-alpine
|
||||||
|
ENV LANG en_US.UTF-8
|
||||||
|
RUN set -eux && sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories &&\
|
||||||
|
apk add tzdata &&\
|
||||||
|
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone &&\
|
||||||
|
apk add --no-cache curl font-adobe-100dpi ttf-dejavu fontconfig &&\
|
||||||
|
apk add libreoffice &&\
|
||||||
|
apk add wget &&\
|
||||||
|
apk add libc6-compat &&\
|
||||||
|
apk add msttcorefonts-installer &&\
|
||||||
|
apk add fontconfig &&\
|
||||||
|
apk --update add unzip &&\
|
||||||
|
mkdir -p /usr/share/fonts/chinese &&\
|
||||||
|
cd /tmp &&\
|
||||||
|
wget http://kkfileview.keking.cn/fonts.zip &&\
|
||||||
|
unzip -d /usr/share/fonts/chinese fonts.zip &&\
|
||||||
|
cd /usr/share/fonts/chinese &&\
|
||||||
|
mkfontscale &&\
|
||||||
|
mkfontdir &&\
|
||||||
|
fc-cache -fv &&\
|
||||||
|
rm -rf /var/cache/*
|
||||||
|
|
||||||
|
COPY ./server/target/crm-print-server-1.0.0.jar /
|
||||||
|
WORKDIR /
|
||||||
|
EXPOSE 9089
|
||||||
|
CMD ["java","-Xms1000m","-Xmx1000m","-jar","crm-print-server-1.0.0.jar"]
|
293
README.md
Normal file
293
README.md
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
|
||||||
|
|
||||||
|
## 合同模板生成
|
||||||
|
|
||||||
|
* 开发地址: http://117.78.50.82:9089
|
||||||
|
* 测试地址: http://192.168.21.31:88/crm-print
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 销售合同
|
||||||
|
|
||||||
|
* 请求路径 /contract/gen/sellContract
|
||||||
|
|
||||||
|
* 请求方法 post
|
||||||
|
|
||||||
|
* 入参
|
||||||
|
|
||||||
|
| 字段 | 名称 | 类型 | 说明 |
|
||||||
|
| ------------------------- | ----------------- | ------ | -------------------------------------------- |
|
||||||
|
| conCode | 合同编号 | string | |
|
||||||
|
| appDate | 签约日期 | string | |
|
||||||
|
| clientName | 采购方 | string | |
|
||||||
|
| registeredAddress | 注册地址 | string | |
|
||||||
|
| taxNumber | 统一社会信用代码 | string | |
|
||||||
|
| paymentMethod | 本合同的付款方式 | string | |
|
||||||
|
| paymentDayOne | 本合同的付款方式1 | string | |
|
||||||
|
| paymentDayTwo | 本合同的付款方式2 | string | |
|
||||||
|
| invoiceType | 增值税 | string | |
|
||||||
|
| qualityDay | 质量验收日 | string | |
|
||||||
|
| responsibility | 违约金日 | string | |
|
||||||
|
| copies | 合同份数 | string | 默认2 |
|
||||||
|
| perCopies | 各执份数 | string | 默认1 |
|
||||||
|
| contractProductDetailVo | 产品详情 | object | |
|
||||||
|
| --\|contractTotalMoney | 合同总金额 | string | |
|
||||||
|
| --\|contractTotalMoneyBig | 合同总金额大写 | string | |
|
||||||
|
| --\|list | 产品明细列表 | array | 如果值为空,请传new ArrayList() ,不要传null |
|
||||||
|
| --\|--\|seqNo | 序号 | string | |
|
||||||
|
| --\|--\|productnum | 货号 | string | |
|
||||||
|
| --\|--\|productname | 产品名 | string | |
|
||||||
|
| --\|--\|spec | 规格 | string | |
|
||||||
|
| --\|--\|salenum | 数量 | string | |
|
||||||
|
| --\|--\|taxprice | 单价 | string | |
|
||||||
|
| --\|--\|sumaell | 小计 | string | |
|
||||||
|
| deliveryTime | 交货时间方式 | string | |
|
||||||
|
| deliveryTimeOne | 交货时间方式1 | string | |
|
||||||
|
| deliveryTimeTwo | 交货时间方式2 | | |
|
||||||
|
| address | 交货地点 | string | |
|
||||||
|
| acceptPhone | 联系电话 | string | |
|
||||||
|
| firstName | 甲方 | string | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* 样例
|
||||||
|
```java{
|
||||||
|
{
|
||||||
|
"conCode": "NJXS000272021090802",
|
||||||
|
"appDate": "2021年09月09日",
|
||||||
|
"clientName": "上海晶旷生物科技有限公司",
|
||||||
|
"registeredAddress": "麓谷企业广场",
|
||||||
|
"taxNumber": "123123123213212313213213",
|
||||||
|
"paymentMethod": "1.1",
|
||||||
|
"paymentDayOne": "3",
|
||||||
|
"paymentDayTwo": "2",
|
||||||
|
"invoiceType": "普通发票",
|
||||||
|
"qualityDay": "3",
|
||||||
|
"responsibility": "五",
|
||||||
|
"copies": "2",
|
||||||
|
"perCopies": "3",
|
||||||
|
"contractProductDetailVo":{
|
||||||
|
"contractTotalMoney": "10",
|
||||||
|
"contractTotalMoneyBig": "10",
|
||||||
|
"list":[
|
||||||
|
{"seqNo":"1","productnum":"03.02.03.0869","productname":"TruePrep® RNA Library Prep Kit for Illumina","spec":"6 rxn","salenum": "1","taxprice": "5","sumaell": "5"},
|
||||||
|
{"seqNo":"2","productnum":"03.02.02.02.0337","productname":"DL2000 Plus DNA Marker","spec":"250 μl","salenum": "1","taxprice": "5","sumaell": "5"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"deliveryTime": "2.1.1",
|
||||||
|
"deliveryTimeOne": "3",
|
||||||
|
"address":"湖北省武汉市硚口区解放大道65号海尔国际广场8号楼22层",
|
||||||
|
"acceptPhone": "18874850463",
|
||||||
|
"firstName": "上海晶旷生物科技有限公"
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
* 出参
|
||||||
|
|
||||||
|
| 字段 | 名称 | 类型 | 说明 |
|
||||||
|
| ---------- | -------- | ------ | ------------------------ |
|
||||||
|
| resultCode | 结果编码 | int | 200 成功,其他失败 |
|
||||||
|
| resultMsg | 结果消息 | string | 结果消息 |
|
||||||
|
| result | 预览地址 | string | 结果成功时才会有预览地址 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* 样例
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```java{
|
||||||
|
"resultMsg": "success",
|
||||||
|
"resultCode": 200,
|
||||||
|
"result": "http://117.78.50.82:9089/onlinePreview?url=aHR0cDovLzExNy43OC41MC44Mjo5MDg5Ly85NmZmZDE3MjU1YzY0YTlkOTdjODA1NzM4NzhiYzFjYS5kb2N4"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 框架合同
|
||||||
|
* 请求路径 /contract/gen/frameContract
|
||||||
|
* 请求方法 post
|
||||||
|
* 入参
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| 字段 | 名称 | 类型 | 说明 |
|
||||||
|
| ------------------- | ---------------- | ------ | -------------------------------------------- |
|
||||||
|
| conCode | 合同编号 | string | |
|
||||||
|
| appDate | 签约日期 | string | |
|
||||||
|
| clientName | 采购方 | string | |
|
||||||
|
| registeredAddress | 注册地址 | string | |
|
||||||
|
| taxNumber | 统一社会信用代码 | string | |
|
||||||
|
| contractPeriodStart | 合同期限开始日期 | string | |
|
||||||
|
| contractPeriodEnd | 合同期限结束日期 | string | |
|
||||||
|
| afterShipDay | 发货日 | string | |
|
||||||
|
| paymentMethod | 合同的付款方式 | string | |
|
||||||
|
| paymentDayOne | 合同的付款方式1 | string | |
|
||||||
|
| paymentDayTwo | 合同的付款方式2 | string | |
|
||||||
|
| checkDay | 验收日 | string | |
|
||||||
|
| validInteInterval | 有效期月 | string | |
|
||||||
|
| responsibility | 违约金额 | string | |
|
||||||
|
| firstName | 甲方 | sring | |
|
||||||
|
| firstRepresentative | 授权代表 | string | |
|
||||||
|
| list | 产品列表 | array | 如果值为空,请传new ArrayList() ,不要传null |
|
||||||
|
| --\|seqNo | 序号 | string | |
|
||||||
|
| --\|productnum | 货号 | string | |
|
||||||
|
| --\|productname | 产品名称 | string | |
|
||||||
|
| --\|spec | 规格 | string | |
|
||||||
|
| --\|taxprice | 单价 | string | |
|
||||||
|
| deliveryTime | 发货方式 | string | |
|
||||||
|
| deliveryTimeOne | 发货方式1 | string | |
|
||||||
|
| deliveryTimeTwo | 发货方式2 | string | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* 样例
|
||||||
|
|
||||||
|
```java{
|
||||||
|
"conCode": "NJXS000272021090802",
|
||||||
|
"appDate": "2021年09月11日",
|
||||||
|
"clientName": "上海晶旷生物科技有限公司",
|
||||||
|
"registeredAddress": "麓谷企业广场",
|
||||||
|
"taxNumber": "123123123213212313213213",
|
||||||
|
"afterShipDay": "5",
|
||||||
|
"contractPeriodStart": "2021年09月09日",
|
||||||
|
"contractPeriodEnd": "2021年09月10日",
|
||||||
|
"paymentMethod": "2",
|
||||||
|
"paymentDayOne": "3%",
|
||||||
|
"checkDay": "3",
|
||||||
|
"validInteInterval": "五",
|
||||||
|
"responsibility":"千分之五",
|
||||||
|
"firstName":"上海晶旷生物科技有限公司",
|
||||||
|
"firstRepresentative": "张三",
|
||||||
|
"list":[
|
||||||
|
{"seqNo":"1","itemNo":"03.02.03.0869","productName":"TruePrep® RNA Library Prep Kit for Illumina","spec":"6 rxn","price": "5"},
|
||||||
|
{"seqNo":"2","itemNo":"03.02.02.02.0337","productName":"DL2000 Plus DNA Marker","spec":"250 μl","price": "5"}
|
||||||
|
],
|
||||||
|
|
||||||
|
"deliveryTime": "2.1.1",
|
||||||
|
"deliveryTimeOne": "3"
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* 出参
|
||||||
|
|
||||||
|
| 字段 | 名称 | 类型 | 说明 |
|
||||||
|
| ---------- | -------- | ------ | ------------------------ |
|
||||||
|
| resultCode | 结果编码 | int | 200 成功,其他失败 |
|
||||||
|
| resultMsg | 结果消息 | string | 结果消息 |
|
||||||
|
| result | 预览地址 | string | 结果成功时才会有预览地址 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* 样例
|
||||||
|
|
||||||
|
```java{
|
||||||
|
"resultMsg": "success",
|
||||||
|
"resultCode": 200,
|
||||||
|
"result": "http://117.78.50.82:9089/onlinePreview?url=aHR0cDovLzExNy43OC41MC44Mjo5MDg5Ly9kYTdhODU5NDhlOWY0MmFjYmFkNTc1MzRlNGFlMGU5NS5kb2N4"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### 合同模板上传
|
||||||
|
|
||||||
|
* 请求方法post
|
||||||
|
* 请求路径 /contract/upload/{templateName}
|
||||||
|
|
||||||
|
* 入参
|
||||||
|
|
||||||
|
| 字段 | 名称 | 类型 | 说明 |
|
||||||
|
| ------------------- | ---------------- | ------ | -------------------------------------------- |
|
||||||
|
| file | 上传文件 | MultipartFile | |
|
||||||
|
| templateName | path变量 | 销售合同 sellContract、框架合同 frameContract|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* 出参
|
||||||
|
|
||||||
|
| 字段 | 名称 | 类型 | 说明 |
|
||||||
|
| ---------- | -------- | ------ | ------------------------ |
|
||||||
|
| resultCode | 结果编码 | int | 200 成功,其他失败 |
|
||||||
|
| resultMsg | 结果消息 | string | 结果消息 |
|
||||||
|
| result | 预览地址 | string | 结果成功时才会有下载地址 |
|
||||||
|
|
||||||
|
|
||||||
|
* 样例
|
||||||
|
|
||||||
|
```java
|
||||||
|
{
|
||||||
|
"resultMsg": "成功",
|
||||||
|
"resultCode": 200,
|
||||||
|
"result": "http://117.78.50.82:9089/crm-print/template/sellContract.docx"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 合同模板下载列表
|
||||||
|
|
||||||
|
* 请求方法post
|
||||||
|
* 请求路径 /contract/list/template
|
||||||
|
|
||||||
|
* 入参
|
||||||
|
|
||||||
|
| 字段 | 名称 | 类型 | 说明 |
|
||||||
|
| ------------------- | ---------------- | ------ | -------------------------------------------- |
|
||||||
|
| templateNames | 所有模板列表 | array | |
|
||||||
|
|
||||||
|
* 样例
|
||||||
|
```java
|
||||||
|
["sellContract","frameContract"]
|
||||||
|
```
|
||||||
|
|
||||||
|
* 出参
|
||||||
|
|
||||||
|
| 字段 | 名称 | 类型 | 说明 |
|
||||||
|
| ---------- | -------- | ------ | ------------------------ |
|
||||||
|
| resultCode | 结果编码 | int | 200 成功,其他失败 |
|
||||||
|
| resultMsg | 结果消息 | string | 结果消息 |
|
||||||
|
| result | 预览地址 | array | 结果成功时才会有下载地址列表 |
|
||||||
|
|
||||||
|
* 样例
|
||||||
|
|
||||||
|
````java
|
||||||
|
{
|
||||||
|
"resultMsg": "成功",
|
||||||
|
"resultCode": 200,
|
||||||
|
"result": [
|
||||||
|
"http://117.78.50.82:9089/crm-print/template/sellContract.docx",
|
||||||
|
"http://117.78.50.82:9089/crm-print/template/frameContract.docx"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
|
||||||
|
## docker部署
|
||||||
|
|
||||||
|
### 需要映射的路径
|
||||||
|
|
||||||
|
* /data/file 文件存储路径
|
||||||
|
* /data/file/cache 缓存路径
|
||||||
|
|
||||||
|
|
||||||
|
* 输出文件预览服务部署文档。
|
||||||
|
* 性能压测。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
12
crm-print.iml
Normal file
12
crm-print.iml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||||
|
<output url="file://$MODULE_DIR$/target/classes" />
|
||||||
|
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
0
fonts/.gitkeep
Normal file
0
fonts/.gitkeep
Normal file
27
office-plugin/office-plugin.iml
Normal file
27
office-plugin/office-plugin.iml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||||
|
<output url="file://$MODULE_DIR$/target/classes" />
|
||||||
|
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="Maven: commons-io:commons-io:2.7" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.openoffice:juh:3.2.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.openoffice:jurt:3.2.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.openoffice:ridl:3.2.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.openoffice:unoil:3.2.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: commons-cli:commons-cli:1.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.hyperic:sigar:1.6.5.132" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.json:json:20090211" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.testng:testng:6.0.1" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:3.8.1" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.beanshell:bsh:2.0b4" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: com.beust:jcommander:1.12" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.yaml:snakeyaml:1.6" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
142
office-plugin/pom.xml
Normal file
142
office-plugin/pom.xml
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.blueland</groupId>
|
||||||
|
<artifactId>crm-print</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>office-plugin</artifactId>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<!-- required for org.hyperic:sigar -->
|
||||||
|
<id>jboss-public-repository-group</id>
|
||||||
|
<url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>2.7</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openoffice</groupId>
|
||||||
|
<artifactId>juh</artifactId>
|
||||||
|
<version>3.2.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openoffice</groupId>
|
||||||
|
<artifactId>ridl</artifactId>
|
||||||
|
<version>3.2.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openoffice</groupId>
|
||||||
|
<artifactId>unoil</artifactId>
|
||||||
|
<version>3.2.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<!-- for the command line tool -->
|
||||||
|
<groupId>commons-cli</groupId>
|
||||||
|
<artifactId>commons-cli</artifactId>
|
||||||
|
<version>1.1</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hyperic</groupId>
|
||||||
|
<artifactId>sigar</artifactId>
|
||||||
|
<version>1.6.5.132</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.json</groupId>
|
||||||
|
<artifactId>json</artifactId>
|
||||||
|
<version>20090211</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testng</groupId>
|
||||||
|
<artifactId>testng</artifactId>
|
||||||
|
<version>6.0.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- 要将源码放上去,需要加入这个插件 -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
<configuration>
|
||||||
|
<attach>true</attach>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.7.2</version>
|
||||||
|
<configuration>
|
||||||
|
<!-- don't run tests in parallel -->
|
||||||
|
<perCoreThreadCount>false</perCoreThreadCount>
|
||||||
|
<threadCount>1</threadCount>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>2.3.1</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>org.artofsolving.jodconverter.cli.Convert</mainClass>
|
||||||
|
<addClasspath>true</addClasspath>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>2.7</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>cobertura-maven-plugin</artifactId>
|
||||||
|
<version>2.4</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</reporting>
|
||||||
|
<!-- distribute目录 -->
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>nexus-releases</id>
|
||||||
|
<name>nexus-releases</name>
|
||||||
|
<url>http://www.rzdata.net:8081/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>nexus-snapshots</id>
|
||||||
|
<name>nexus-snapshots</name>
|
||||||
|
<url>http://www.rzdata.net:8081/repository/maven-snapshots/</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
</project>
|
37
office-plugin/src/main/assembly/dist.xml
Normal file
37
office-plugin/src/main/assembly/dist.xml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<assembly>
|
||||||
|
<id>dist</id>
|
||||||
|
<formats>
|
||||||
|
<format>zip</format>
|
||||||
|
</formats>
|
||||||
|
<dependencySets>
|
||||||
|
<dependencySet>
|
||||||
|
<outputDirectory>lib</outputDirectory>
|
||||||
|
<excludes>
|
||||||
|
<exclude>org.hyperic:sigar</exclude>
|
||||||
|
</excludes>
|
||||||
|
</dependencySet>
|
||||||
|
</dependencySets>
|
||||||
|
<fileSets>
|
||||||
|
<fileSet>
|
||||||
|
<includes>
|
||||||
|
<include>LICENSE.txt</include>
|
||||||
|
<include>README.txt</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>target</directory>
|
||||||
|
<outputDirectory>/</outputDirectory>
|
||||||
|
<includes>
|
||||||
|
<include>${project.artifactId}-${project.version}-javadoc.jar</include>
|
||||||
|
<include>${project.artifactId}-${project.version}-sources.jar</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<outputDirectory>/conf</outputDirectory>
|
||||||
|
<includes>
|
||||||
|
<include>document-formats.js</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
</fileSets>
|
||||||
|
</assembly>
|
@ -0,0 +1,125 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter;
|
||||||
|
|
||||||
|
import static org.artofsolving.jodconverter.office.OfficeUtils.SERVICE_DESKTOP;
|
||||||
|
import static org.artofsolving.jodconverter.office.OfficeUtils.cast;
|
||||||
|
import static org.artofsolving.jodconverter.office.OfficeUtils.toUnoProperties;
|
||||||
|
import static org.artofsolving.jodconverter.office.OfficeUtils.toUrl;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.artofsolving.jodconverter.office.OfficeContext;
|
||||||
|
import org.artofsolving.jodconverter.office.OfficeException;
|
||||||
|
import org.artofsolving.jodconverter.office.OfficeTask;
|
||||||
|
|
||||||
|
import com.sun.star.frame.XComponentLoader;
|
||||||
|
import com.sun.star.frame.XStorable;
|
||||||
|
import com.sun.star.io.IOException;
|
||||||
|
import com.sun.star.lang.IllegalArgumentException;
|
||||||
|
import com.sun.star.lang.XComponent;
|
||||||
|
import com.sun.star.task.ErrorCodeIOException;
|
||||||
|
import com.sun.star.util.CloseVetoException;
|
||||||
|
import com.sun.star.util.XCloseable;
|
||||||
|
|
||||||
|
public abstract class AbstractConversionTask implements OfficeTask {
|
||||||
|
|
||||||
|
private final File inputFile;
|
||||||
|
private final File outputFile;
|
||||||
|
|
||||||
|
public AbstractConversionTask(File inputFile, File outputFile) {
|
||||||
|
this.inputFile = inputFile;
|
||||||
|
this.outputFile = outputFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Map<String,?> getLoadProperties(File inputFile);
|
||||||
|
|
||||||
|
protected abstract Map<String,?> getStoreProperties(File outputFile, XComponent document);
|
||||||
|
|
||||||
|
public void execute(OfficeContext context) throws OfficeException {
|
||||||
|
XComponent document = null;
|
||||||
|
try {
|
||||||
|
document = loadDocument(context, inputFile);
|
||||||
|
modifyDocument(document);
|
||||||
|
storeDocument(document, outputFile);
|
||||||
|
} catch (OfficeException officeException) {
|
||||||
|
throw officeException;
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new OfficeException("conversion failed", exception);
|
||||||
|
} finally {
|
||||||
|
if (document != null) {
|
||||||
|
XCloseable closeable = cast(XCloseable.class, document);
|
||||||
|
if (closeable != null) {
|
||||||
|
try {
|
||||||
|
closeable.close(true);
|
||||||
|
} catch (CloseVetoException closeVetoException) {
|
||||||
|
// whoever raised the veto should close the document
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
document.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private XComponent loadDocument(OfficeContext context, File inputFile) throws OfficeException {
|
||||||
|
if (!inputFile.exists()) {
|
||||||
|
throw new OfficeException("input document not found");
|
||||||
|
}
|
||||||
|
XComponentLoader loader = cast(XComponentLoader.class, context.getService(SERVICE_DESKTOP));
|
||||||
|
Map<String,?> loadProperties = getLoadProperties(inputFile);
|
||||||
|
XComponent document = null;
|
||||||
|
try {
|
||||||
|
document = loader.loadComponentFromURL(toUrl(inputFile), "_blank", 0, toUnoProperties(loadProperties));
|
||||||
|
} catch (IllegalArgumentException illegalArgumentException) {
|
||||||
|
throw new OfficeException("could not load document: " + inputFile.getName(), illegalArgumentException);
|
||||||
|
} catch (ErrorCodeIOException errorCodeIOException) {
|
||||||
|
throw new OfficeException("could not load document: " + inputFile.getName() + "; errorCode: " + errorCodeIOException.ErrCode, errorCodeIOException);
|
||||||
|
} catch (IOException ioException) {
|
||||||
|
throw new OfficeException("could not load document: " + inputFile.getName(), ioException);
|
||||||
|
}
|
||||||
|
if (document == null) {
|
||||||
|
throw new OfficeException("could not load document: " + inputFile.getName());
|
||||||
|
}
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override to modify the document after it has been loaded and before it gets
|
||||||
|
* saved in the new format.
|
||||||
|
* <p>
|
||||||
|
* Does nothing by default.
|
||||||
|
*
|
||||||
|
* @param document
|
||||||
|
* @throws OfficeException
|
||||||
|
*/
|
||||||
|
protected void modifyDocument(XComponent document) throws OfficeException {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storeDocument(XComponent document, File outputFile) throws OfficeException {
|
||||||
|
Map<String,?> storeProperties = getStoreProperties(outputFile, document);
|
||||||
|
if (storeProperties == null) {
|
||||||
|
throw new OfficeException("unsupported conversion");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
cast(XStorable.class, document).storeToURL(toUrl(outputFile), toUnoProperties(storeProperties));
|
||||||
|
} catch (ErrorCodeIOException errorCodeIOException) {
|
||||||
|
throw new OfficeException("could not store document: " + outputFile.getName() + "; errorCode: " + errorCodeIOException.ErrCode, errorCodeIOException);
|
||||||
|
} catch (IOException ioException) {
|
||||||
|
throw new OfficeException("could not store document: " + outputFile.getName(), ioException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.artofsolving.jodconverter.document.DefaultDocumentFormatRegistry;
|
||||||
|
import org.artofsolving.jodconverter.document.DocumentFormat;
|
||||||
|
import org.artofsolving.jodconverter.document.DocumentFormatRegistry;
|
||||||
|
import org.artofsolving.jodconverter.office.OfficeException;
|
||||||
|
import org.artofsolving.jodconverter.office.OfficeManager;
|
||||||
|
|
||||||
|
import com.sun.star.document.UpdateDocMode;
|
||||||
|
|
||||||
|
public class OfficeDocumentConverter {
|
||||||
|
|
||||||
|
private final OfficeManager officeManager;
|
||||||
|
private final DocumentFormatRegistry formatRegistry;
|
||||||
|
|
||||||
|
private Map<String,?> defaultLoadProperties = createDefaultLoadProperties();
|
||||||
|
|
||||||
|
public OfficeDocumentConverter(OfficeManager officeManager) {
|
||||||
|
this(officeManager, new DefaultDocumentFormatRegistry());
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfficeDocumentConverter(OfficeManager officeManager, DocumentFormatRegistry formatRegistry) {
|
||||||
|
this.officeManager = officeManager;
|
||||||
|
this.formatRegistry = formatRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String,Object> createDefaultLoadProperties() {
|
||||||
|
Map<String,Object> loadProperties = new HashMap<String,Object>();
|
||||||
|
loadProperties.put("Hidden", true);
|
||||||
|
loadProperties.put("ReadOnly", true);
|
||||||
|
loadProperties.put("UpdateDocMode", UpdateDocMode.QUIET_UPDATE);
|
||||||
|
return loadProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultLoadProperties(Map<String, ?> defaultLoadProperties) {
|
||||||
|
this.defaultLoadProperties = defaultLoadProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentFormatRegistry getFormatRegistry() {
|
||||||
|
return formatRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void convert(File inputFile, File outputFile) throws OfficeException {
|
||||||
|
String outputExtension = FilenameUtils.getExtension(outputFile.getName());
|
||||||
|
DocumentFormat outputFormat = formatRegistry.getFormatByExtension(outputExtension);
|
||||||
|
convert(inputFile, outputFile, outputFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void convert(File inputFile, File outputFile, DocumentFormat outputFormat) throws OfficeException {
|
||||||
|
String inputExtension = FilenameUtils.getExtension(inputFile.getName());
|
||||||
|
DocumentFormat inputFormat = formatRegistry.getFormatByExtension(inputExtension);
|
||||||
|
StandardConversionTask conversionTask = new StandardConversionTask(inputFile, outputFile, outputFormat);
|
||||||
|
conversionTask.setDefaultLoadProperties(defaultLoadProperties);
|
||||||
|
conversionTask.setInputFormat(inputFormat);
|
||||||
|
officeManager.execute(conversionTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter;
|
||||||
|
|
||||||
|
import static org.artofsolving.jodconverter.office.OfficeUtils.*;
|
||||||
|
|
||||||
|
import org.artofsolving.jodconverter.document.DocumentFamily;
|
||||||
|
import org.artofsolving.jodconverter.office.OfficeException;
|
||||||
|
|
||||||
|
|
||||||
|
import com.sun.star.lang.XComponent;
|
||||||
|
import com.sun.star.lang.XServiceInfo;
|
||||||
|
|
||||||
|
class OfficeDocumentUtils {
|
||||||
|
|
||||||
|
private OfficeDocumentUtils() {
|
||||||
|
throw new AssertionError("utility class must not be instantiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DocumentFamily getDocumentFamily(XComponent document) throws OfficeException {
|
||||||
|
XServiceInfo serviceInfo = cast(XServiceInfo.class, document);
|
||||||
|
if (serviceInfo.supportsService("com.sun.star.text.GenericTextDocument")) {
|
||||||
|
// NOTE: a GenericTextDocument is either a TextDocument, a WebDocument, or a GlobalDocument
|
||||||
|
// but this further distinction doesn't seem to matter for conversions
|
||||||
|
return DocumentFamily.TEXT;
|
||||||
|
} else if (serviceInfo.supportsService("com.sun.star.sheet.SpreadsheetDocument")) {
|
||||||
|
return DocumentFamily.SPREADSHEET;
|
||||||
|
} else if (serviceInfo.supportsService("com.sun.star.presentation.PresentationDocument")) {
|
||||||
|
return DocumentFamily.PRESENTATION;
|
||||||
|
} else if (serviceInfo.supportsService("com.sun.star.drawing.DrawingDocument")) {
|
||||||
|
return DocumentFamily.DRAWING;
|
||||||
|
} else {
|
||||||
|
throw new OfficeException("document of unknown family: " + serviceInfo.getImplementationName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter;
|
||||||
|
|
||||||
|
import static org.artofsolving.jodconverter.office.OfficeUtils.cast;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.artofsolving.jodconverter.document.DocumentFamily;
|
||||||
|
import org.artofsolving.jodconverter.document.DocumentFormat;
|
||||||
|
import org.artofsolving.jodconverter.office.OfficeException;
|
||||||
|
|
||||||
|
import com.sun.star.lang.XComponent;
|
||||||
|
import com.sun.star.util.XRefreshable;
|
||||||
|
|
||||||
|
public class StandardConversionTask extends AbstractConversionTask {
|
||||||
|
|
||||||
|
private final DocumentFormat outputFormat;
|
||||||
|
|
||||||
|
private Map<String,?> defaultLoadProperties;
|
||||||
|
private DocumentFormat inputFormat;
|
||||||
|
|
||||||
|
public StandardConversionTask(File inputFile, File outputFile, DocumentFormat outputFormat) {
|
||||||
|
super(inputFile, outputFile);
|
||||||
|
this.outputFormat = outputFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultLoadProperties(Map<String, ?> defaultLoadProperties) {
|
||||||
|
this.defaultLoadProperties = defaultLoadProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInputFormat(DocumentFormat inputFormat) {
|
||||||
|
this.inputFormat = inputFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void modifyDocument(XComponent document) throws OfficeException {
|
||||||
|
XRefreshable refreshable = cast(XRefreshable.class, document);
|
||||||
|
if (refreshable != null) {
|
||||||
|
refreshable.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String,?> getLoadProperties(File inputFile) {
|
||||||
|
Map<String,Object> loadProperties = new HashMap<String,Object>();
|
||||||
|
if (defaultLoadProperties != null) {
|
||||||
|
loadProperties.putAll(defaultLoadProperties);
|
||||||
|
}
|
||||||
|
if (inputFormat != null && inputFormat.getLoadProperties() != null) {
|
||||||
|
loadProperties.putAll(inputFormat.getLoadProperties());
|
||||||
|
}
|
||||||
|
return loadProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String,?> getStoreProperties(File outputFile, XComponent document) {
|
||||||
|
DocumentFamily family = OfficeDocumentUtils.getDocumentFamily(document);
|
||||||
|
return outputFormat.getStoreProperties(family);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.cli;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.commons.cli.CommandLine;
|
||||||
|
import org.apache.commons.cli.CommandLineParser;
|
||||||
|
import org.apache.commons.cli.HelpFormatter;
|
||||||
|
import org.apache.commons.cli.Option;
|
||||||
|
import org.apache.commons.cli.Options;
|
||||||
|
import org.apache.commons.cli.ParseException;
|
||||||
|
import org.apache.commons.cli.PosixParser;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.artofsolving.jodconverter.OfficeDocumentConverter;
|
||||||
|
import org.artofsolving.jodconverter.document.DefaultDocumentFormatRegistry;
|
||||||
|
import org.artofsolving.jodconverter.document.DocumentFormatRegistry;
|
||||||
|
import org.artofsolving.jodconverter.document.JsonDocumentFormatRegistry;
|
||||||
|
import org.artofsolving.jodconverter.office.OfficeManager;
|
||||||
|
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
|
||||||
|
import org.json.JSONException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command line interface executable.
|
||||||
|
*/
|
||||||
|
public class Convert {
|
||||||
|
|
||||||
|
public static final int STATUS_OK = 0;
|
||||||
|
public static final int STATUS_MISSING_INPUT_FILE = 1;
|
||||||
|
public static final int STATUS_INVALID_ARGUMENTS = 255;
|
||||||
|
|
||||||
|
private static final Option OPTION_OUTPUT_FORMAT = new Option("o", "output-format", true, "output format (e.g. pdf)");
|
||||||
|
private static final Option OPTION_PORT = new Option("p", "port", true, "office socket port (optional; defaults to 2002)");
|
||||||
|
private static final Option OPTION_REGISTRY = new Option("r", "registry", true, "document formats registry configuration file (optional)");
|
||||||
|
private static final Option OPTION_TIMEOUT = new Option("t", "timeout", true, "maximum conversion time in seconds (optional; defaults to 120)");
|
||||||
|
private static final Option OPTION_USER_PROFILE = new Option("u", "user-profile", true, "use settings from the given user installation dir (optional)");
|
||||||
|
private static final Options OPTIONS = initOptions();
|
||||||
|
|
||||||
|
private static final int DEFAULT_OFFICE_PORT = 2002;
|
||||||
|
|
||||||
|
private static Options initOptions() {
|
||||||
|
Options options = new Options();
|
||||||
|
options.addOption(OPTION_OUTPUT_FORMAT);
|
||||||
|
options.addOption(OPTION_PORT);
|
||||||
|
options.addOption(OPTION_REGISTRY);
|
||||||
|
options.addOption(OPTION_TIMEOUT);
|
||||||
|
options.addOption(OPTION_USER_PROFILE);
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] arguments) throws ParseException, JSONException, IOException {
|
||||||
|
CommandLineParser commandLineParser = new PosixParser();
|
||||||
|
CommandLine commandLine = commandLineParser.parse(OPTIONS, arguments);
|
||||||
|
|
||||||
|
String outputFormat = null;
|
||||||
|
if (commandLine.hasOption(OPTION_OUTPUT_FORMAT.getOpt())) {
|
||||||
|
outputFormat = commandLine.getOptionValue(OPTION_OUTPUT_FORMAT.getOpt());
|
||||||
|
}
|
||||||
|
|
||||||
|
int port = DEFAULT_OFFICE_PORT;
|
||||||
|
if (commandLine.hasOption(OPTION_PORT.getOpt())) {
|
||||||
|
port = Integer.parseInt(commandLine.getOptionValue(OPTION_PORT.getOpt()));
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] fileNames = commandLine.getArgs();
|
||||||
|
if ((outputFormat == null && fileNames.length != 2) || fileNames.length < 1) {
|
||||||
|
String syntax = "java -jar jodconverter-core.jar [options] input-file output-file\n"
|
||||||
|
+ "or [options] -o output-format input-file [input-file...]";
|
||||||
|
HelpFormatter helpFormatter = new HelpFormatter();
|
||||||
|
helpFormatter.printHelp(syntax, OPTIONS);
|
||||||
|
System.exit(STATUS_INVALID_ARGUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentFormatRegistry registry;
|
||||||
|
if (commandLine.hasOption(OPTION_REGISTRY.getOpt())) {
|
||||||
|
File registryFile = new File(commandLine.getOptionValue(OPTION_REGISTRY.getOpt()));
|
||||||
|
registry = new JsonDocumentFormatRegistry(FileUtils.readFileToString(registryFile));
|
||||||
|
} else {
|
||||||
|
registry = new DefaultDocumentFormatRegistry();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
|
||||||
|
configuration.setPortNumber(port);
|
||||||
|
if (commandLine.hasOption(OPTION_TIMEOUT.getOpt())) {
|
||||||
|
int timeout = Integer.parseInt(commandLine.getOptionValue(OPTION_TIMEOUT.getOpt()));
|
||||||
|
configuration.setTaskExecutionTimeout(timeout * 1000);
|
||||||
|
}
|
||||||
|
if (commandLine.hasOption(OPTION_USER_PROFILE.getOpt())) {
|
||||||
|
String templateProfileDir = commandLine.getOptionValue(OPTION_USER_PROFILE.getOpt());
|
||||||
|
configuration.setTemplateProfileDir(new File(templateProfileDir));
|
||||||
|
}
|
||||||
|
|
||||||
|
OfficeManager officeManager = configuration.buildOfficeManager();
|
||||||
|
officeManager.start();
|
||||||
|
OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager, registry);
|
||||||
|
try {
|
||||||
|
if (outputFormat == null) {
|
||||||
|
File inputFile = new File(fileNames[0]);
|
||||||
|
File outputFile = new File(fileNames[1]);
|
||||||
|
converter.convert(inputFile, outputFile);
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < fileNames.length; i++) {
|
||||||
|
File inputFile = new File(fileNames[i]);
|
||||||
|
String outputName = FilenameUtils.getBaseName(fileNames[i]) + "." + outputFormat;
|
||||||
|
File outputFile = new File(FilenameUtils.getFullPath(fileNames[i]) + outputName);
|
||||||
|
converter.convert(inputFile, outputFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
officeManager.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,157 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.document;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DefaultDocumentFormatRegistry extends SimpleDocumentFormatRegistry {
|
||||||
|
|
||||||
|
public DefaultDocumentFormatRegistry() {
|
||||||
|
DocumentFormat pdf = new DocumentFormat("Portable Document Format", "pdf", "application/pdf");
|
||||||
|
pdf.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "writer_pdf_Export"));
|
||||||
|
pdf.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "calc_pdf_Export"));
|
||||||
|
pdf.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_pdf_Export"));
|
||||||
|
pdf.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_pdf_Export"));
|
||||||
|
addFormat(pdf);
|
||||||
|
|
||||||
|
DocumentFormat swf = new DocumentFormat("Macromedia Flash", "swf", "application/x-shockwave-flash");
|
||||||
|
swf.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_flash_Export"));
|
||||||
|
swf.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_flash_Export"));
|
||||||
|
addFormat(swf);
|
||||||
|
|
||||||
|
// disabled because it's not always available
|
||||||
|
//DocumentFormat xhtml = new DocumentFormat("XHTML", "xhtml", "application/xhtml+xml");
|
||||||
|
//xhtml.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "XHTML Writer File"));
|
||||||
|
//xhtml.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "XHTML Calc File"));
|
||||||
|
//xhtml.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "XHTML Impress File"));
|
||||||
|
//addFormat(xhtml);
|
||||||
|
|
||||||
|
DocumentFormat html = new DocumentFormat("HTML", "html", "text/html");
|
||||||
|
// HTML is treated as Text when supplied as input, but as an output it is also
|
||||||
|
// available for exporting Spreadsheet and Presentation formats
|
||||||
|
html.setInputFamily(DocumentFamily.TEXT);
|
||||||
|
html.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "HTML (StarWriter)"));
|
||||||
|
html.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "HTML (StarCalc)"));
|
||||||
|
html.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_html_Export"));
|
||||||
|
addFormat(html);
|
||||||
|
|
||||||
|
DocumentFormat odt = new DocumentFormat("OpenDocument Text", "odt", "application/vnd.oasis.opendocument.text");
|
||||||
|
odt.setInputFamily(DocumentFamily.TEXT);
|
||||||
|
odt.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "writer8"));
|
||||||
|
addFormat(odt);
|
||||||
|
|
||||||
|
DocumentFormat sxw = new DocumentFormat("OpenOffice.org 1.0 Text Document", "sxw", "application/vnd.sun.xml.writer");
|
||||||
|
sxw.setInputFamily(DocumentFamily.TEXT);
|
||||||
|
sxw.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "StarOffice XML (Writer)"));
|
||||||
|
addFormat(sxw);
|
||||||
|
|
||||||
|
DocumentFormat doc = new DocumentFormat("Microsoft Word", "doc", "application/msword");
|
||||||
|
doc.setInputFamily(DocumentFamily.TEXT);
|
||||||
|
doc.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "MS Word 97"));
|
||||||
|
addFormat(doc);
|
||||||
|
|
||||||
|
DocumentFormat docx = new DocumentFormat("Microsoft Word 2007 XML", "docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
|
||||||
|
docx.setInputFamily(DocumentFamily.TEXT);
|
||||||
|
addFormat(docx);
|
||||||
|
|
||||||
|
DocumentFormat rtf = new DocumentFormat("Rich Text Format", "rtf", "text/rtf");
|
||||||
|
rtf.setInputFamily(DocumentFamily.TEXT);
|
||||||
|
rtf.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "Rich Text Format"));
|
||||||
|
addFormat(rtf);
|
||||||
|
|
||||||
|
DocumentFormat wpd = new DocumentFormat("WordPerfect", "wpd", "application/wordperfect");
|
||||||
|
wpd.setInputFamily(DocumentFamily.TEXT);
|
||||||
|
addFormat(wpd);
|
||||||
|
|
||||||
|
DocumentFormat txt = new DocumentFormat("Plain Text", "txt", "text/plain");
|
||||||
|
txt.setInputFamily(DocumentFamily.TEXT);
|
||||||
|
Map<String,Object> txtLoadAndStoreProperties = new LinkedHashMap<String,Object>();
|
||||||
|
txtLoadAndStoreProperties.put("FilterName", "Text (encoded)");
|
||||||
|
txtLoadAndStoreProperties.put("FilterOptions", "utf8");
|
||||||
|
txt.setLoadProperties(txtLoadAndStoreProperties);
|
||||||
|
txt.setStoreProperties(DocumentFamily.TEXT, txtLoadAndStoreProperties);
|
||||||
|
addFormat(txt);
|
||||||
|
|
||||||
|
DocumentFormat wikitext = new DocumentFormat("MediaWiki wikitext", "wiki", "text/x-wiki");
|
||||||
|
wikitext.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "MediaWiki"));
|
||||||
|
//addFormat(wikitext);
|
||||||
|
|
||||||
|
DocumentFormat ods = new DocumentFormat("OpenDocument Spreadsheet", "ods", "application/vnd.oasis.opendocument.spreadsheet");
|
||||||
|
ods.setInputFamily(DocumentFamily.SPREADSHEET);
|
||||||
|
ods.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "calc8"));
|
||||||
|
addFormat(ods);
|
||||||
|
|
||||||
|
DocumentFormat sxc = new DocumentFormat("OpenOffice.org 1.0 Spreadsheet", "sxc", "application/vnd.sun.xml.calc");
|
||||||
|
sxc.setInputFamily(DocumentFamily.SPREADSHEET);
|
||||||
|
sxc.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "StarOffice XML (Calc)"));
|
||||||
|
addFormat(sxc);
|
||||||
|
|
||||||
|
DocumentFormat xls = new DocumentFormat("Microsoft Excel", "xls", "application/vnd.ms-excel");
|
||||||
|
xls.setInputFamily(DocumentFamily.SPREADSHEET);
|
||||||
|
xls.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "MS Excel 97"));
|
||||||
|
addFormat(xls);
|
||||||
|
|
||||||
|
DocumentFormat xlsx = new DocumentFormat("Microsoft Excel 2007 XML", "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||||
|
xlsx.setInputFamily(DocumentFamily.SPREADSHEET);
|
||||||
|
addFormat(xlsx);
|
||||||
|
|
||||||
|
DocumentFormat csv = new DocumentFormat("Comma Separated Values", "csv", "text/csv");
|
||||||
|
csv.setInputFamily(DocumentFamily.SPREADSHEET);
|
||||||
|
Map<String,Object> csvLoadAndStoreProperties = new LinkedHashMap<String,Object>();
|
||||||
|
csvLoadAndStoreProperties.put("FilterName", "Text - txt - csv (StarCalc)");
|
||||||
|
csvLoadAndStoreProperties.put("FilterOptions", "44,34,0"); // Field Separator: ','; Text Delimiter: '"'
|
||||||
|
csv.setLoadProperties(csvLoadAndStoreProperties);
|
||||||
|
csv.setStoreProperties(DocumentFamily.SPREADSHEET, csvLoadAndStoreProperties);
|
||||||
|
addFormat(csv);
|
||||||
|
|
||||||
|
DocumentFormat tsv = new DocumentFormat("Tab Separated Values", "tsv", "text/tab-separated-values");
|
||||||
|
tsv.setInputFamily(DocumentFamily.SPREADSHEET);
|
||||||
|
Map<String,Object> tsvLoadAndStoreProperties = new LinkedHashMap<String,Object>();
|
||||||
|
tsvLoadAndStoreProperties.put("FilterName", "Text - txt - csv (StarCalc)");
|
||||||
|
tsvLoadAndStoreProperties.put("FilterOptions", "9,34,0"); // Field Separator: '\t'; Text Delimiter: '"'
|
||||||
|
tsv.setLoadProperties(tsvLoadAndStoreProperties);
|
||||||
|
tsv.setStoreProperties(DocumentFamily.SPREADSHEET, tsvLoadAndStoreProperties);
|
||||||
|
addFormat(tsv);
|
||||||
|
|
||||||
|
DocumentFormat odp = new DocumentFormat("OpenDocument Presentation", "odp", "application/vnd.oasis.opendocument.presentation");
|
||||||
|
odp.setInputFamily(DocumentFamily.PRESENTATION);
|
||||||
|
odp.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress8"));
|
||||||
|
addFormat(odp);
|
||||||
|
|
||||||
|
DocumentFormat sxi = new DocumentFormat("OpenOffice.org 1.0 Presentation", "sxi", "application/vnd.sun.xml.impress");
|
||||||
|
sxi.setInputFamily(DocumentFamily.PRESENTATION);
|
||||||
|
sxi.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "StarOffice XML (Impress)"));
|
||||||
|
addFormat(sxi);
|
||||||
|
|
||||||
|
DocumentFormat ppt = new DocumentFormat("Microsoft PowerPoint", "ppt", "application/vnd.ms-powerpoint");
|
||||||
|
ppt.setInputFamily(DocumentFamily.PRESENTATION);
|
||||||
|
ppt.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "MS PowerPoint 97"));
|
||||||
|
addFormat(ppt);
|
||||||
|
|
||||||
|
DocumentFormat pptx = new DocumentFormat("Microsoft PowerPoint 2007 XML", "pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
|
||||||
|
pptx.setInputFamily(DocumentFamily.PRESENTATION);
|
||||||
|
addFormat(pptx);
|
||||||
|
|
||||||
|
DocumentFormat odg = new DocumentFormat("OpenDocument Drawing", "odg", "application/vnd.oasis.opendocument.graphics");
|
||||||
|
odg.setInputFamily(DocumentFamily.DRAWING);
|
||||||
|
odg.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw8"));
|
||||||
|
addFormat(odg);
|
||||||
|
|
||||||
|
DocumentFormat svg = new DocumentFormat("Scalable Vector Graphics", "svg", "image/svg+xml");
|
||||||
|
svg.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_svg_Export"));
|
||||||
|
addFormat(svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.document;
|
||||||
|
|
||||||
|
public enum DocumentFamily {
|
||||||
|
|
||||||
|
TEXT, SPREADSHEET, PRESENTATION, DRAWING
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.document;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DocumentFormat {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String extension;
|
||||||
|
private String mediaType;
|
||||||
|
private DocumentFamily inputFamily;
|
||||||
|
private Map<String,?> loadProperties;
|
||||||
|
private Map<DocumentFamily,Map<String,?>> storePropertiesByFamily;
|
||||||
|
|
||||||
|
public DocumentFormat() {
|
||||||
|
// default
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentFormat(String name, String extension, String mediaType) {
|
||||||
|
this.name = name;
|
||||||
|
this.extension = extension;
|
||||||
|
this.mediaType = mediaType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExtension() {
|
||||||
|
return extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtension(String extension) {
|
||||||
|
this.extension = extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMediaType() {
|
||||||
|
return mediaType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaType(String mediaType) {
|
||||||
|
this.mediaType = mediaType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentFamily getInputFamily() {
|
||||||
|
return inputFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInputFamily(DocumentFamily documentFamily) {
|
||||||
|
this.inputFamily = documentFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, ?> getLoadProperties() {
|
||||||
|
return loadProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoadProperties(Map<String,?> loadProperties) {
|
||||||
|
this.loadProperties = loadProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<DocumentFamily, Map<String, ?>> getStorePropertiesByFamily() {
|
||||||
|
return storePropertiesByFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStorePropertiesByFamily(Map<DocumentFamily, Map<String,?>> storePropertiesByFamily) {
|
||||||
|
this.storePropertiesByFamily = storePropertiesByFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStoreProperties(DocumentFamily family, Map<String,?> storeProperties) {
|
||||||
|
if (storePropertiesByFamily == null) {
|
||||||
|
storePropertiesByFamily = new HashMap<DocumentFamily,Map<String,?>>();
|
||||||
|
}
|
||||||
|
storePropertiesByFamily.put(family, storeProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String,?> getStoreProperties(DocumentFamily family) {
|
||||||
|
if (storePropertiesByFamily == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return storePropertiesByFamily.get(family);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.document;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface DocumentFormatRegistry {
|
||||||
|
|
||||||
|
public DocumentFormat getFormatByExtension(String extension);
|
||||||
|
|
||||||
|
public DocumentFormat getFormatByMediaType(String mediaType);
|
||||||
|
|
||||||
|
public Set<DocumentFormat> getOutputFormats(DocumentFamily family);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.document;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
public class JsonDocumentFormatRegistry extends SimpleDocumentFormatRegistry {
|
||||||
|
|
||||||
|
public JsonDocumentFormatRegistry(InputStream input) throws JSONException, IOException {
|
||||||
|
readJsonArray(IOUtils.toString(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonDocumentFormatRegistry(String source) throws JSONException {
|
||||||
|
readJsonArray(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readJsonArray(String source) throws JSONException {
|
||||||
|
JSONArray array = new JSONArray(source);
|
||||||
|
for (int i = 0; i < array.length(); i++) {
|
||||||
|
JSONObject jsonFormat = array.getJSONObject(i);
|
||||||
|
DocumentFormat format = new DocumentFormat();
|
||||||
|
format.setName(jsonFormat.getString("name"));
|
||||||
|
format.setExtension(jsonFormat.getString("extension"));
|
||||||
|
format.setMediaType(jsonFormat.getString("mediaType"));
|
||||||
|
if (jsonFormat.has("inputFamily")) {
|
||||||
|
format.setInputFamily(DocumentFamily.valueOf(jsonFormat.getString("inputFamily")));
|
||||||
|
}
|
||||||
|
if (jsonFormat.has("loadProperties")) {
|
||||||
|
format.setLoadProperties(toJavaMap(jsonFormat.getJSONObject("loadProperties")));
|
||||||
|
}
|
||||||
|
if (jsonFormat.has("storePropertiesByFamily")) {
|
||||||
|
JSONObject jsonStorePropertiesByFamily = jsonFormat.getJSONObject("storePropertiesByFamily");
|
||||||
|
for (String key : JSONObject.getNames(jsonStorePropertiesByFamily)) {
|
||||||
|
Map<String,?> storeProperties = toJavaMap(jsonStorePropertiesByFamily.getJSONObject(key));
|
||||||
|
format.setStoreProperties(DocumentFamily.valueOf(key), storeProperties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addFormat(format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String,?> toJavaMap(JSONObject jsonMap) throws JSONException {
|
||||||
|
Map<String,Object> map = new HashMap<String,Object>();
|
||||||
|
for (String key : JSONObject.getNames(jsonMap)) {
|
||||||
|
Object value = jsonMap.get(key);
|
||||||
|
if (value instanceof JSONObject) {
|
||||||
|
map.put(key, toJavaMap((JSONObject) value));
|
||||||
|
} else {
|
||||||
|
map.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.document;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class SimpleDocumentFormatRegistry implements DocumentFormatRegistry {
|
||||||
|
|
||||||
|
private List<DocumentFormat> documentFormats = new ArrayList<DocumentFormat>();
|
||||||
|
|
||||||
|
public void addFormat(DocumentFormat documentFormat) {
|
||||||
|
documentFormats.add(documentFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentFormat getFormatByExtension(String extension) {
|
||||||
|
if (extension == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String lowerExtension = extension.toLowerCase();
|
||||||
|
//TODO keep a documentByExtension map instead
|
||||||
|
for (DocumentFormat format : documentFormats) {
|
||||||
|
if (format.getExtension().equals(lowerExtension)) {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentFormat getFormatByMediaType(String mediaType) {
|
||||||
|
if (mediaType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//TODO keep a documentByMediaType map instead
|
||||||
|
for (DocumentFormat format : documentFormats) {
|
||||||
|
if (format.getMediaType().equals(mediaType)) {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<DocumentFormat> getOutputFormats(DocumentFamily family) {
|
||||||
|
Set<DocumentFormat> formats = new HashSet<DocumentFormat>();
|
||||||
|
for (DocumentFormat format : documentFormats) {
|
||||||
|
if (format.getStoreProperties(family) != null) {
|
||||||
|
formats.add(format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return formats;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,223 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.artofsolving.jodconverter.process.ProcessManager;
|
||||||
|
import org.artofsolving.jodconverter.process.PureJavaProcessManager;
|
||||||
|
import org.artofsolving.jodconverter.process.LinuxProcessManager;
|
||||||
|
import org.artofsolving.jodconverter.process.SigarProcessManager;
|
||||||
|
import org.artofsolving.jodconverter.util.PlatformUtils;
|
||||||
|
|
||||||
|
public class DefaultOfficeManagerConfiguration {
|
||||||
|
|
||||||
|
public static final long DEFAULT_RETRY_TIMEOUT = 120000L;
|
||||||
|
|
||||||
|
private File officeHome = OfficeUtils.getDefaultOfficeHome();
|
||||||
|
private OfficeConnectionProtocol connectionProtocol = OfficeConnectionProtocol.SOCKET;
|
||||||
|
private int[] portNumbers = new int[] { 2002 };
|
||||||
|
private String[] pipeNames = new String[] { "office" };
|
||||||
|
private String[] runAsArgs = null;
|
||||||
|
private File templateProfileDir = null;
|
||||||
|
private File workDir = new File(System.getProperty("java.io.tmpdir"));
|
||||||
|
private long taskQueueTimeout = 30000L; // 30 seconds
|
||||||
|
private long taskExecutionTimeout = 120000L; // 2 minutes
|
||||||
|
private int maxTasksPerProcess = 200;
|
||||||
|
private long retryTimeout = DEFAULT_RETRY_TIMEOUT;
|
||||||
|
|
||||||
|
private ProcessManager processManager = null; // lazily initialised
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setOfficeHome(String officeHome) throws NullPointerException, IllegalArgumentException {
|
||||||
|
checkArgumentNotNull("officeHome", officeHome);
|
||||||
|
return setOfficeHome(new File(officeHome));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setOfficeHome(File officeHome) throws NullPointerException, IllegalArgumentException {
|
||||||
|
checkArgumentNotNull("officeHome", officeHome);
|
||||||
|
checkArgument("officeHome", officeHome.isDirectory(), "must exist and be a directory");
|
||||||
|
this.officeHome = officeHome;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setConnectionProtocol(OfficeConnectionProtocol connectionProtocol) throws NullPointerException {
|
||||||
|
checkArgumentNotNull("connectionProtocol", connectionProtocol);
|
||||||
|
this.connectionProtocol = connectionProtocol;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setPortNumber(int portNumber) {
|
||||||
|
this.portNumbers = new int[] { portNumber };
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setPortNumbers(int... portNumbers) throws NullPointerException, IllegalArgumentException {
|
||||||
|
checkArgumentNotNull("portNumbers", portNumbers);
|
||||||
|
checkArgument("portNumbers", portNumbers.length > 0, "must not be empty");
|
||||||
|
this.portNumbers = portNumbers;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setPipeName(String pipeName) throws NullPointerException {
|
||||||
|
checkArgumentNotNull("pipeName", pipeName);
|
||||||
|
this.pipeNames = new String[] { pipeName };
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setPipeNames(String... pipeNames) throws NullPointerException, IllegalArgumentException {
|
||||||
|
checkArgumentNotNull("pipeNames", pipeNames);
|
||||||
|
checkArgument("pipeNames", pipeNames.length > 0, "must not be empty");
|
||||||
|
this.pipeNames = pipeNames;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setRunAsArgs(String... runAsArgs) {
|
||||||
|
this.runAsArgs = runAsArgs;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setTemplateProfileDir(File templateProfileDir) throws IllegalArgumentException {
|
||||||
|
if (templateProfileDir != null) {
|
||||||
|
checkArgument("templateProfileDir", templateProfileDir.isDirectory(), "must exist and be a directory");
|
||||||
|
}
|
||||||
|
this.templateProfileDir = templateProfileDir;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the directory where temporary office profiles will be created.
|
||||||
|
* <p>
|
||||||
|
* Defaults to the system temporary directory as specified by the <code>java.io.tmpdir</code> system property.
|
||||||
|
*
|
||||||
|
* @param workDir
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DefaultOfficeManagerConfiguration setWorkDir(File workDir) {
|
||||||
|
checkArgumentNotNull("workDir", workDir);
|
||||||
|
this.workDir = workDir;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setTaskQueueTimeout(long taskQueueTimeout) {
|
||||||
|
this.taskQueueTimeout = taskQueueTimeout;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setTaskExecutionTimeout(long taskExecutionTimeout) {
|
||||||
|
this.taskExecutionTimeout = taskExecutionTimeout;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultOfficeManagerConfiguration setMaxTasksPerProcess(int maxTasksPerProcess) {
|
||||||
|
this.maxTasksPerProcess = maxTasksPerProcess;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide a specific {@link ProcessManager} implementation
|
||||||
|
* <p>
|
||||||
|
* The default is to use {@link SigarProcessManager} if sigar.jar is
|
||||||
|
* available in the classpath, otherwise {@link LinuxProcessManager}
|
||||||
|
* on Linux and {@link PureJavaProcessManager} on other platforms.
|
||||||
|
*
|
||||||
|
* @param processManager
|
||||||
|
* @return
|
||||||
|
* @throws NullPointerException
|
||||||
|
*/
|
||||||
|
public DefaultOfficeManagerConfiguration setProcessManager(ProcessManager processManager) throws NullPointerException {
|
||||||
|
checkArgumentNotNull("processManager", processManager);
|
||||||
|
this.processManager = processManager;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retry timeout set in milliseconds. Used for retrying office process calls.
|
||||||
|
* If not set, it defaults to 2 minutes
|
||||||
|
*
|
||||||
|
* @param retryTimeout in milliseconds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DefaultOfficeManagerConfiguration setRetryTimeout(long retryTimeout) {
|
||||||
|
this.retryTimeout = retryTimeout;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfficeManager buildOfficeManager() throws IllegalStateException {
|
||||||
|
if (officeHome == null) {
|
||||||
|
throw new IllegalStateException("officeHome not set and could not be auto-detected");
|
||||||
|
} else if (!officeHome.isDirectory()) {
|
||||||
|
throw new IllegalStateException("officeHome doesn't exist or is not a directory: " + officeHome);
|
||||||
|
} else if (!OfficeUtils.getOfficeExecutable(officeHome).isFile()) {
|
||||||
|
throw new IllegalStateException("invalid officeHome: it doesn't contain soffice.bin: " + officeHome);
|
||||||
|
}
|
||||||
|
if (templateProfileDir != null && !isValidProfileDir(templateProfileDir)) {
|
||||||
|
throw new IllegalStateException("templateProfileDir doesn't appear to contain a user profile: " + templateProfileDir);
|
||||||
|
}
|
||||||
|
if (!workDir.isDirectory()) {
|
||||||
|
throw new IllegalStateException("workDir doesn't exist or is not a directory: " + workDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (processManager == null) {
|
||||||
|
processManager = findBestProcessManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
int numInstances = connectionProtocol == OfficeConnectionProtocol.PIPE ? pipeNames.length : portNumbers.length;
|
||||||
|
UnoUrl[] unoUrls = new UnoUrl[numInstances];
|
||||||
|
for (int i = 0; i < numInstances; i++) {
|
||||||
|
unoUrls[i] = (connectionProtocol == OfficeConnectionProtocol.PIPE) ? UnoUrl.pipe(pipeNames[i]) : UnoUrl.socket(portNumbers[i]);
|
||||||
|
}
|
||||||
|
return new ProcessPoolOfficeManager(officeHome, unoUrls, runAsArgs, templateProfileDir, workDir, retryTimeout, taskQueueTimeout, taskExecutionTimeout, maxTasksPerProcess, processManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProcessManager findBestProcessManager() {
|
||||||
|
if (isSigarAvailable()) {
|
||||||
|
return new SigarProcessManager();
|
||||||
|
} else if (PlatformUtils.isLinux()) {
|
||||||
|
LinuxProcessManager processManager = new LinuxProcessManager();
|
||||||
|
if (runAsArgs != null) {
|
||||||
|
processManager.setRunAsArgs(runAsArgs);
|
||||||
|
}
|
||||||
|
return processManager;
|
||||||
|
} else {
|
||||||
|
// NOTE: UnixProcessManager can't be trusted to work on Solaris
|
||||||
|
// because of the 80-char limit on ps output there
|
||||||
|
return new PureJavaProcessManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSigarAvailable() {
|
||||||
|
try {
|
||||||
|
Class.forName("org.hyperic.sigar.Sigar", false, getClass().getClassLoader());
|
||||||
|
return true;
|
||||||
|
} catch (ClassNotFoundException classNotFoundException) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkArgumentNotNull(String argName, Object argValue) throws NullPointerException {
|
||||||
|
if (argValue == null) {
|
||||||
|
throw new NullPointerException(argName + " must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkArgument(String argName, boolean condition, String message) throws IllegalArgumentException {
|
||||||
|
if (!condition) {
|
||||||
|
throw new IllegalArgumentException(argName + " " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidProfileDir(File profileDir) {
|
||||||
|
return new File(profileDir, "user").isDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.net.ConnectException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link OfficeManager} implementation that connects to an external Office process.
|
||||||
|
* <p>
|
||||||
|
* The external Office process needs to be started manually, e.g. from the command line with
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* soffice -accept="socket,host=127.0.0.1,port=2002;urp;"
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Since this implementation does not manage the Office process, it does not support auto-restarting the process if it exits unexpectedly.
|
||||||
|
* <p>
|
||||||
|
* It will however auto-reconnect to the external process if the latter is manually restarted.
|
||||||
|
* <p>
|
||||||
|
* This {@link OfficeManager} implementation basically provides the same behaviour as JODConverter 2.x, including using <em>synchronized</em> blocks for serialising office
|
||||||
|
* operations.
|
||||||
|
*/
|
||||||
|
class ExternalOfficeManager implements OfficeManager {
|
||||||
|
|
||||||
|
private final OfficeConnection connection;
|
||||||
|
private final boolean connectOnStart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param unoUrl
|
||||||
|
* @param connectOnStart
|
||||||
|
* should a connection be attempted on {@link #start()}? Default is <em>true</em>. If <em>false</em>, a connection will only be attempted the first time an
|
||||||
|
* {@link OfficeTask} is executed.
|
||||||
|
*/
|
||||||
|
public ExternalOfficeManager(UnoUrl unoUrl, boolean connectOnStart) {
|
||||||
|
connection = new OfficeConnection(unoUrl);
|
||||||
|
this.connectOnStart = connectOnStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() throws OfficeException {
|
||||||
|
if (connectOnStart) {
|
||||||
|
synchronized (connection) {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
synchronized (connection) {
|
||||||
|
if (connection.isConnected()) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(OfficeTask task) throws OfficeException {
|
||||||
|
synchronized (connection) {
|
||||||
|
if (!connection.isConnected()) {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
task.execute(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connect() {
|
||||||
|
try {
|
||||||
|
connection.connect();
|
||||||
|
} catch (ConnectException connectException) {
|
||||||
|
throw new OfficeException("could not connect to external office process", connectException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning() {
|
||||||
|
return connection.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
public class ExternalOfficeManagerConfiguration {
|
||||||
|
|
||||||
|
private OfficeConnectionProtocol connectionProtocol = OfficeConnectionProtocol.SOCKET;
|
||||||
|
private int portNumber = 2002;
|
||||||
|
private String pipeName = "office";
|
||||||
|
private boolean connectOnStart = true;
|
||||||
|
|
||||||
|
public ExternalOfficeManagerConfiguration setConnectionProtocol(OfficeConnectionProtocol connectionProtocol) {
|
||||||
|
this.connectionProtocol = connectionProtocol;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalOfficeManagerConfiguration setPortNumber(int portNumber) {
|
||||||
|
this.portNumber = portNumber;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalOfficeManagerConfiguration setPipeName(String pipeName) {
|
||||||
|
this.pipeName = pipeName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalOfficeManagerConfiguration setConnectOnStart(boolean connectOnStart) {
|
||||||
|
this.connectOnStart = connectOnStart;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfficeManager buildOfficeManager() {
|
||||||
|
UnoUrl unoUrl = connectionProtocol == OfficeConnectionProtocol.SOCKET ? UnoUrl.socket(portNumber) : UnoUrl.pipe(pipeName);
|
||||||
|
return new ExternalOfficeManager(unoUrl, connectOnStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,176 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.net.ConnectException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.sun.star.frame.XDesktop;
|
||||||
|
import com.sun.star.lang.DisposedException;
|
||||||
|
|
||||||
|
class ManagedOfficeProcess {
|
||||||
|
|
||||||
|
private static final Integer EXIT_CODE_NEW_INSTALLATION = Integer.valueOf(81);
|
||||||
|
|
||||||
|
private final ManagedOfficeProcessSettings settings;
|
||||||
|
|
||||||
|
private final OfficeProcess process;
|
||||||
|
private final OfficeConnection connection;
|
||||||
|
|
||||||
|
private ExecutorService executor = Executors.newSingleThreadExecutor(new NamedThreadFactory("OfficeProcessThread"));
|
||||||
|
|
||||||
|
private final Logger logger = Logger.getLogger(getClass().getName());
|
||||||
|
|
||||||
|
public ManagedOfficeProcess(ManagedOfficeProcessSettings settings) throws OfficeException {
|
||||||
|
this.settings = settings;
|
||||||
|
process = new OfficeProcess(settings.getOfficeHome(), settings.getUnoUrl(), settings.getRunAsArgs(), settings.getTemplateProfileDir(), settings.getWorkDir(), settings
|
||||||
|
.getProcessManager());
|
||||||
|
connection = new OfficeConnection(settings.getUnoUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfficeConnection getConnection() {
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startAndWait() throws OfficeException {
|
||||||
|
Future<?> future = executor.submit(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
doStartProcessAndConnect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
future.get();
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new OfficeException("failed to start and connect", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopAndWait() throws OfficeException {
|
||||||
|
Future<?> future = executor.submit(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
doStopProcess();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
future.get();
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new OfficeException("failed to start and connect", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restartAndWait() {
|
||||||
|
Future<?> future = executor.submit(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
doStopProcess();
|
||||||
|
doStartProcessAndConnect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
future.get();
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new OfficeException("failed to restart", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restartDueToTaskTimeout() {
|
||||||
|
executor.execute(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
doTerminateProcess();
|
||||||
|
// will cause unexpected disconnection and subsequent restart
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restartDueToLostConnection() {
|
||||||
|
executor.execute(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
doEnsureProcessExited();
|
||||||
|
doStartProcessAndConnect();
|
||||||
|
} catch (OfficeException officeException) {
|
||||||
|
logger.log(Level.SEVERE, "could not restart process", officeException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doStartProcessAndConnect() throws OfficeException {
|
||||||
|
try {
|
||||||
|
process.start();
|
||||||
|
new Retryable() {
|
||||||
|
protected void attempt() throws TemporaryException, Exception {
|
||||||
|
try {
|
||||||
|
connection.connect();
|
||||||
|
} catch (ConnectException connectException) {
|
||||||
|
Integer exitCode = process.getExitCode();
|
||||||
|
if (exitCode == null) {
|
||||||
|
// process is running; retry later
|
||||||
|
throw new TemporaryException(connectException);
|
||||||
|
} else if (exitCode.equals(EXIT_CODE_NEW_INSTALLATION)) {
|
||||||
|
// restart and retry later
|
||||||
|
// see http://code.google.com/p/jodconverter/issues/detail?id=84
|
||||||
|
logger.log(Level.WARNING, "office process died with exit code 81; restarting it");
|
||||||
|
process.start(true);
|
||||||
|
throw new TemporaryException(connectException);
|
||||||
|
} else {
|
||||||
|
throw new OfficeException("office process died with exit code " + exitCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute(settings.getRetryInterval(), settings.getRetryTimeout());
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new OfficeException("could not establish connection", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doStopProcess() {
|
||||||
|
try {
|
||||||
|
XDesktop desktop = OfficeUtils.cast(XDesktop.class, connection.getService(OfficeUtils.SERVICE_DESKTOP));
|
||||||
|
desktop.terminate();
|
||||||
|
} catch (DisposedException disposedException) {
|
||||||
|
// expected
|
||||||
|
} catch (Exception exception) {
|
||||||
|
// in case we can't get hold of the desktop
|
||||||
|
doTerminateProcess();
|
||||||
|
}
|
||||||
|
doEnsureProcessExited();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doEnsureProcessExited() throws OfficeException {
|
||||||
|
try {
|
||||||
|
int exitCode = process.getExitCode(settings.getRetryInterval(), settings.getRetryTimeout());
|
||||||
|
logger.info("process exited with code " + exitCode);
|
||||||
|
} catch (RetryTimeoutException retryTimeoutException) {
|
||||||
|
doTerminateProcess();
|
||||||
|
}
|
||||||
|
process.deleteProfileDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTerminateProcess() throws OfficeException {
|
||||||
|
try {
|
||||||
|
int exitCode = process.forciblyTerminate(settings.getRetryInterval(), settings.getRetryTimeout());
|
||||||
|
logger.info("process forcibly terminated with code " + exitCode);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new OfficeException("could not terminate process", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isConnected() {
|
||||||
|
return connection.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.artofsolving.jodconverter.process.ProcessManager;
|
||||||
|
import org.artofsolving.jodconverter.process.PureJavaProcessManager;
|
||||||
|
|
||||||
|
class ManagedOfficeProcessSettings {
|
||||||
|
|
||||||
|
public static final long DEFAULT_RETRY_INTERVAL = 250L;
|
||||||
|
|
||||||
|
private final UnoUrl unoUrl;
|
||||||
|
private File officeHome = OfficeUtils.getDefaultOfficeHome();
|
||||||
|
private String[] runAsArgs;
|
||||||
|
private File templateProfileDir;
|
||||||
|
private File workDir = new File(System.getProperty("java.io.tmpdir"));
|
||||||
|
private ProcessManager processManager = new PureJavaProcessManager();
|
||||||
|
private long retryTimeout = DefaultOfficeManagerConfiguration.DEFAULT_RETRY_TIMEOUT;
|
||||||
|
private long retryInterval = DEFAULT_RETRY_INTERVAL;
|
||||||
|
|
||||||
|
public ManagedOfficeProcessSettings(UnoUrl unoUrl) {
|
||||||
|
this.unoUrl = unoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnoUrl getUnoUrl() {
|
||||||
|
return unoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getOfficeHome() {
|
||||||
|
return officeHome;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOfficeHome(File officeHome) {
|
||||||
|
this.officeHome = officeHome;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getRunAsArgs() {
|
||||||
|
return runAsArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRunAsArgs(String[] runAsArgs) {
|
||||||
|
this.runAsArgs = runAsArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getTemplateProfileDir() {
|
||||||
|
return templateProfileDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemplateProfileDir(File templateProfileDir) {
|
||||||
|
this.templateProfileDir = templateProfileDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getWorkDir() {
|
||||||
|
return workDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWorkDir(File workDir) {
|
||||||
|
this.workDir = workDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProcessManager getProcessManager() {
|
||||||
|
return processManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProcessManager(ProcessManager processManager) {
|
||||||
|
this.processManager = processManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRetryTimeout() {
|
||||||
|
return retryTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRetryTimeout(long retryTimeout) {
|
||||||
|
this.retryTimeout = retryTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRetryInterval() {
|
||||||
|
return retryInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRetryInterval(long retryInterval) {
|
||||||
|
this.retryInterval = retryInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ThreadFactory} that allows for custom thread names
|
||||||
|
*/
|
||||||
|
class NamedThreadFactory implements ThreadFactory {
|
||||||
|
|
||||||
|
private static final AtomicInteger threadIndex = new AtomicInteger(0);
|
||||||
|
|
||||||
|
private final String baseName;
|
||||||
|
private final boolean daemon;
|
||||||
|
|
||||||
|
public NamedThreadFactory(String baseName) {
|
||||||
|
this(baseName, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamedThreadFactory(String baseName, boolean daemon) {
|
||||||
|
this.baseName = baseName;
|
||||||
|
this.daemon = daemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Thread newThread(Runnable runnable) {
|
||||||
|
Thread thread = new Thread(runnable, baseName + "-" + threadIndex.getAndIncrement());
|
||||||
|
thread.setDaemon(daemon);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.net.ConnectException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.sun.star.beans.XPropertySet;
|
||||||
|
import com.sun.star.bridge.XBridge;
|
||||||
|
import com.sun.star.bridge.XBridgeFactory;
|
||||||
|
import com.sun.star.comp.helper.Bootstrap;
|
||||||
|
import com.sun.star.connection.NoConnectException;
|
||||||
|
import com.sun.star.connection.XConnection;
|
||||||
|
import com.sun.star.connection.XConnector;
|
||||||
|
import com.sun.star.lang.EventObject;
|
||||||
|
import com.sun.star.lang.XComponent;
|
||||||
|
import com.sun.star.lang.XEventListener;
|
||||||
|
import com.sun.star.lang.XMultiComponentFactory;
|
||||||
|
import com.sun.star.uno.XComponentContext;
|
||||||
|
|
||||||
|
class OfficeConnection implements OfficeContext {
|
||||||
|
|
||||||
|
private static AtomicInteger bridgeIndex = new AtomicInteger();
|
||||||
|
|
||||||
|
private final UnoUrl unoUrl;
|
||||||
|
|
||||||
|
private XComponent bridgeComponent;
|
||||||
|
private XMultiComponentFactory serviceManager;
|
||||||
|
private XComponentContext componentContext;
|
||||||
|
|
||||||
|
private final List<OfficeConnectionEventListener> connectionEventListeners = new ArrayList<OfficeConnectionEventListener>();
|
||||||
|
|
||||||
|
private volatile boolean connected = false;
|
||||||
|
|
||||||
|
private XEventListener bridgeListener = new XEventListener() {
|
||||||
|
public void disposing(EventObject event) {
|
||||||
|
if (connected) {
|
||||||
|
connected = false;
|
||||||
|
logger.info(String.format("disconnected: '%s'", unoUrl));
|
||||||
|
OfficeConnectionEvent connectionEvent = new OfficeConnectionEvent(OfficeConnection.this);
|
||||||
|
for (OfficeConnectionEventListener listener : connectionEventListeners) {
|
||||||
|
listener.disconnected(connectionEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else we tried to connect to a server that doesn't speak URP
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final Logger logger = Logger.getLogger(getClass().getName());
|
||||||
|
|
||||||
|
public OfficeConnection(UnoUrl unoUrl) {
|
||||||
|
this.unoUrl = unoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addConnectionEventListener(OfficeConnectionEventListener connectionEventListener) {
|
||||||
|
connectionEventListeners.add(connectionEventListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect() throws ConnectException {
|
||||||
|
logger.fine(String.format("connecting with connectString '%s'", unoUrl));
|
||||||
|
try {
|
||||||
|
XComponentContext localContext = Bootstrap.createInitialComponentContext(null);
|
||||||
|
XMultiComponentFactory localServiceManager = localContext.getServiceManager();
|
||||||
|
XConnector connector = OfficeUtils.cast(XConnector.class, localServiceManager.createInstanceWithContext("com.sun.star.connection.Connector", localContext));
|
||||||
|
XConnection connection = connector.connect(unoUrl.getConnectString());
|
||||||
|
XBridgeFactory bridgeFactory = OfficeUtils.cast(XBridgeFactory.class, localServiceManager.createInstanceWithContext("com.sun.star.bridge.BridgeFactory", localContext));
|
||||||
|
String bridgeName = "jodconverter_" + bridgeIndex.getAndIncrement();
|
||||||
|
XBridge bridge = bridgeFactory.createBridge(bridgeName, "urp", connection, null);
|
||||||
|
bridgeComponent = OfficeUtils.cast(XComponent.class, bridge);
|
||||||
|
bridgeComponent.addEventListener(bridgeListener);
|
||||||
|
serviceManager = OfficeUtils.cast(XMultiComponentFactory.class, bridge.getInstance("StarOffice.ServiceManager"));
|
||||||
|
XPropertySet properties = OfficeUtils.cast(XPropertySet.class, serviceManager);
|
||||||
|
componentContext = OfficeUtils.cast(XComponentContext.class, properties.getPropertyValue("DefaultContext"));
|
||||||
|
connected = true;
|
||||||
|
logger.info(String.format("connected: '%s'", unoUrl));
|
||||||
|
OfficeConnectionEvent connectionEvent = new OfficeConnectionEvent(this);
|
||||||
|
for (OfficeConnectionEventListener listener : connectionEventListeners) {
|
||||||
|
listener.connected(connectionEvent);
|
||||||
|
}
|
||||||
|
} catch (NoConnectException connectException) {
|
||||||
|
throw new ConnectException(String.format("connection failed: '%s'; %s", unoUrl, connectException.getMessage()));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new OfficeException("connection failed: "+ unoUrl, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
return connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void disconnect() {
|
||||||
|
logger.fine(String.format("disconnecting: '%s'", unoUrl));
|
||||||
|
bridgeComponent.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getService(String serviceName) {
|
||||||
|
try {
|
||||||
|
return serviceManager.createInstanceWithContext(serviceName, componentContext);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new OfficeException(String.format("failed to obtain service '%s'", serviceName), exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.util.EventObject;
|
||||||
|
|
||||||
|
class OfficeConnectionEvent extends EventObject {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 2060652797570876077L;
|
||||||
|
|
||||||
|
public OfficeConnectionEvent(OfficeConnection source) {
|
||||||
|
super(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.util.EventListener;
|
||||||
|
|
||||||
|
interface OfficeConnectionEventListener extends EventListener {
|
||||||
|
|
||||||
|
void connected(OfficeConnectionEvent event);
|
||||||
|
|
||||||
|
void disconnected(OfficeConnectionEvent event);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
public enum OfficeConnectionProtocol { PIPE, SOCKET }
|
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
public interface OfficeContext {
|
||||||
|
|
||||||
|
Object getService(String serviceName);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
public class OfficeException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public OfficeException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfficeException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An OfficeManager knows how to execute {@link OfficeTask}s.
|
||||||
|
* <p>
|
||||||
|
* An OfficeManager implementation will typically manage one or more
|
||||||
|
* {@link OfficeConnection}s.
|
||||||
|
*/
|
||||||
|
public interface OfficeManager {
|
||||||
|
|
||||||
|
void execute(OfficeTask task) throws OfficeException;
|
||||||
|
|
||||||
|
void start() throws OfficeException;
|
||||||
|
|
||||||
|
void stop() throws OfficeException;
|
||||||
|
|
||||||
|
boolean isRunning();
|
||||||
|
}
|
@ -0,0 +1,209 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import static org.artofsolving.jodconverter.process.ProcessManager.PID_NOT_FOUND;
|
||||||
|
import static org.artofsolving.jodconverter.process.ProcessManager.PID_UNKNOWN;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.artofsolving.jodconverter.process.ProcessManager;
|
||||||
|
import org.artofsolving.jodconverter.process.ProcessQuery;
|
||||||
|
import org.artofsolving.jodconverter.util.PlatformUtils;
|
||||||
|
|
||||||
|
class OfficeProcess {
|
||||||
|
|
||||||
|
private final File officeHome;
|
||||||
|
private final UnoUrl unoUrl;
|
||||||
|
private final String[] runAsArgs;
|
||||||
|
private final File templateProfileDir;
|
||||||
|
private final File instanceProfileDir;
|
||||||
|
private final ProcessManager processManager;
|
||||||
|
|
||||||
|
private Process process;
|
||||||
|
private long pid = PID_UNKNOWN;
|
||||||
|
|
||||||
|
private final Logger logger = Logger.getLogger(getClass().getName());
|
||||||
|
|
||||||
|
public OfficeProcess(File officeHome, UnoUrl unoUrl, String[] runAsArgs, File templateProfileDir, File workDir, ProcessManager processManager) {
|
||||||
|
this.officeHome = officeHome;
|
||||||
|
this.unoUrl = unoUrl;
|
||||||
|
this.runAsArgs = runAsArgs;
|
||||||
|
this.templateProfileDir = templateProfileDir;
|
||||||
|
this.instanceProfileDir = getInstanceProfileDir(workDir, unoUrl);
|
||||||
|
this.processManager = processManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() throws IOException {
|
||||||
|
start(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(boolean restart) throws IOException {
|
||||||
|
ProcessQuery processQuery = new ProcessQuery("soffice.bin", unoUrl.getAcceptString());
|
||||||
|
long existingPid = processManager.findPid(processQuery);
|
||||||
|
if (!(existingPid == PID_NOT_FOUND || existingPid == PID_UNKNOWN)) {
|
||||||
|
throw new IllegalStateException(String.format("a process with acceptString '%s' is already running; pid %d",
|
||||||
|
unoUrl.getAcceptString(), existingPid));
|
||||||
|
}
|
||||||
|
if (!restart) {
|
||||||
|
prepareInstanceProfileDir();
|
||||||
|
}
|
||||||
|
List<String> command = new ArrayList<String>();
|
||||||
|
File executable = OfficeUtils.getOfficeExecutable(officeHome);
|
||||||
|
if (runAsArgs != null) {
|
||||||
|
command.addAll(Arrays.asList(runAsArgs));
|
||||||
|
}
|
||||||
|
command.add(executable.getAbsolutePath());
|
||||||
|
command.add("-accept=" + unoUrl.getAcceptString() + ";urp;");
|
||||||
|
command.add("-env:UserInstallation=" + OfficeUtils.toUrl(instanceProfileDir));
|
||||||
|
command.add("-headless");
|
||||||
|
command.add("-nocrashreport");
|
||||||
|
command.add("-nodefault");
|
||||||
|
command.add("-nofirststartwizard");
|
||||||
|
command.add("-nolockcheck");
|
||||||
|
command.add("-nologo");
|
||||||
|
command.add("-norestore");
|
||||||
|
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||||
|
if (PlatformUtils.isWindows()) {
|
||||||
|
addBasisAndUrePaths(processBuilder);
|
||||||
|
}
|
||||||
|
logger.info(String.format("starting process with acceptString '%s' and profileDir '%s'", unoUrl, instanceProfileDir));
|
||||||
|
process = processBuilder.start();
|
||||||
|
pid = processManager.findPid(processQuery);
|
||||||
|
if (pid == PID_NOT_FOUND) {
|
||||||
|
throw new IllegalStateException(String.format("process with acceptString '%s' started but its pid could not be found",
|
||||||
|
unoUrl.getAcceptString()));
|
||||||
|
}
|
||||||
|
logger.info("started process" + (pid != PID_UNKNOWN ? "; pid = " + pid : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getInstanceProfileDir(File workDir, UnoUrl unoUrl) {
|
||||||
|
String dirName = ".jodconverter_" + unoUrl.getAcceptString().replace(',', '_').replace('=', '-');
|
||||||
|
return new File(workDir, dirName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareInstanceProfileDir() throws OfficeException {
|
||||||
|
if (instanceProfileDir.exists()) {
|
||||||
|
logger.warning(String.format("profile dir '%s' already exists; deleting", instanceProfileDir));
|
||||||
|
deleteProfileDir();
|
||||||
|
}
|
||||||
|
if (templateProfileDir != null) {
|
||||||
|
try {
|
||||||
|
FileUtils.copyDirectory(templateProfileDir, instanceProfileDir);
|
||||||
|
} catch (IOException ioException) {
|
||||||
|
throw new OfficeException("failed to create profileDir", ioException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteProfileDir() {
|
||||||
|
if (instanceProfileDir != null) {
|
||||||
|
try {
|
||||||
|
FileUtils.deleteDirectory(instanceProfileDir);
|
||||||
|
} catch (IOException ioException) {
|
||||||
|
File oldProfileDir = new File(instanceProfileDir.getParentFile(), instanceProfileDir.getName() + ".old." + System.currentTimeMillis());
|
||||||
|
if (instanceProfileDir.renameTo(oldProfileDir)) {
|
||||||
|
logger.warning("could not delete profileDir: " + ioException.getMessage() + "; renamed it to " + oldProfileDir);
|
||||||
|
} else {
|
||||||
|
logger.severe("could not delete profileDir: " + ioException.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addBasisAndUrePaths(ProcessBuilder processBuilder) throws IOException {
|
||||||
|
// see http://wiki.services.openoffice.org/wiki/ODF_Toolkit/Efforts/Three-Layer_OOo
|
||||||
|
File basisLink = new File(officeHome, "basis-link");
|
||||||
|
if (!basisLink.isFile()) {
|
||||||
|
logger.fine("no %OFFICE_HOME%/basis-link found; assuming it's OOo 2.x and we don't need to append URE and Basic paths");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String basisLinkText = FileUtils.readFileToString(basisLink).trim();
|
||||||
|
File basisHome = new File(officeHome, basisLinkText);
|
||||||
|
File basisProgram = new File(basisHome, "program");
|
||||||
|
File ureLink = new File(basisHome, "ure-link");
|
||||||
|
String ureLinkText = FileUtils.readFileToString(ureLink).trim();
|
||||||
|
File ureHome = new File(basisHome, ureLinkText);
|
||||||
|
File ureBin = new File(ureHome, "bin");
|
||||||
|
Map<String,String> environment = processBuilder.environment();
|
||||||
|
// Windows environment variables are case insensitive but Java maps are not :-/
|
||||||
|
// so let's make sure we modify the existing key
|
||||||
|
String pathKey = "PATH";
|
||||||
|
for (String key : environment.keySet()) {
|
||||||
|
if ("PATH".equalsIgnoreCase(key)) {
|
||||||
|
pathKey = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String path = environment.get(pathKey) + ";" + ureBin.getAbsolutePath() + ";" + basisProgram.getAbsolutePath();
|
||||||
|
logger.fine(String.format("setting %s to \"%s\"", pathKey, path));
|
||||||
|
environment.put(pathKey, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning() {
|
||||||
|
if (process == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return getExitCode() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ExitCodeRetryable extends Retryable {
|
||||||
|
|
||||||
|
private int exitCode;
|
||||||
|
|
||||||
|
protected void attempt() throws TemporaryException, Exception {
|
||||||
|
try {
|
||||||
|
exitCode = process.exitValue();
|
||||||
|
} catch (IllegalThreadStateException illegalThreadStateException) {
|
||||||
|
throw new TemporaryException(illegalThreadStateException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getExitCode() {
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getExitCode() {
|
||||||
|
try {
|
||||||
|
return process.exitValue();
|
||||||
|
} catch (IllegalThreadStateException exception) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getExitCode(long retryInterval, long retryTimeout) throws RetryTimeoutException {
|
||||||
|
try {
|
||||||
|
ExitCodeRetryable retryable = new ExitCodeRetryable();
|
||||||
|
retryable.execute(retryInterval, retryTimeout);
|
||||||
|
return retryable.getExitCode();
|
||||||
|
} catch (RetryTimeoutException retryTimeoutException) {
|
||||||
|
throw retryTimeoutException;
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new OfficeException("could not get process exit code", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int forciblyTerminate(long retryInterval, long retryTimeout) throws IOException, RetryTimeoutException {
|
||||||
|
logger.info(String.format("trying to forcibly terminate process: '" + unoUrl + "'" + (pid != PID_UNKNOWN ? " (pid " + pid + ")" : "")));
|
||||||
|
processManager.kill(process, pid);
|
||||||
|
return getExitCode(retryInterval, retryTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
public interface OfficeTask {
|
||||||
|
|
||||||
|
void execute(OfficeContext context) throws OfficeException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,171 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.artofsolving.jodconverter.util.ConfigUtils;
|
||||||
|
import org.artofsolving.jodconverter.util.PlatformUtils;
|
||||||
|
|
||||||
|
import com.sun.star.beans.PropertyValue;
|
||||||
|
import com.sun.star.uno.UnoRuntime;
|
||||||
|
|
||||||
|
public class OfficeUtils {
|
||||||
|
|
||||||
|
public static final String SERVICE_DESKTOP = "com.sun.star.frame.Desktop";
|
||||||
|
//todo 替换officeHome
|
||||||
|
public static final String OFFICE_HOME_KEY = "office.home";
|
||||||
|
public static final String DEFAULT_OFFICE_HOME_VALUE = "default";
|
||||||
|
|
||||||
|
private OfficeUtils() {
|
||||||
|
throw new AssertionError("utility class must not be instantiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T cast(Class<T> type, Object object) {
|
||||||
|
return (T) UnoRuntime.queryInterface(type, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyValue property(String name, Object value) {
|
||||||
|
PropertyValue propertyValue = new PropertyValue();
|
||||||
|
propertyValue.Name = name;
|
||||||
|
propertyValue.Value = value;
|
||||||
|
return propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static PropertyValue[] toUnoProperties(Map<String,?> properties) {
|
||||||
|
PropertyValue[] propertyValues = new PropertyValue[properties.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (Map.Entry<String,?> entry : properties.entrySet()) {
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value instanceof Map) {
|
||||||
|
Map<String,Object> subProperties = (Map<String,Object>) value;
|
||||||
|
value = toUnoProperties(subProperties);
|
||||||
|
}
|
||||||
|
propertyValues[i++] = property(entry.getKey(), value);
|
||||||
|
}
|
||||||
|
return propertyValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toUrl(File file) {
|
||||||
|
String path = file.toURI().getRawPath();
|
||||||
|
String url = path.startsWith("//") ? "file:" + path : "file://" + path;
|
||||||
|
return url.endsWith("/") ? url.substring(0, url.length() - 1) : url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File getDefaultOfficeHome() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
String customizedConfigPath = ConfigUtils.getCustomizedConfigPath();
|
||||||
|
try {
|
||||||
|
BufferedReader bufferedReader = new BufferedReader(new FileReader(customizedConfigPath));
|
||||||
|
properties.load(bufferedReader);
|
||||||
|
restorePropertiesFromEnvFormat(properties);
|
||||||
|
} catch (Exception e) {}
|
||||||
|
String officeHome = properties.getProperty(OFFICE_HOME_KEY);
|
||||||
|
if (officeHome != null && !DEFAULT_OFFICE_HOME_VALUE.equals(officeHome)) {
|
||||||
|
return new File(officeHome);
|
||||||
|
}
|
||||||
|
if (PlatformUtils.isWindows()) {
|
||||||
|
// %ProgramFiles(x86)% on 64-bit machines; %ProgramFiles% on 32-bit ones
|
||||||
|
String officePluginPath = ConfigUtils.getOfficePluginPath();
|
||||||
|
String programFiles = System.getenv("ProgramFiles(x86)");
|
||||||
|
if (programFiles == null) {
|
||||||
|
programFiles = System.getenv("ProgramFiles");
|
||||||
|
}
|
||||||
|
return findOfficeHome(
|
||||||
|
officePluginPath + File.separator + "windows-office",
|
||||||
|
programFiles + File.separator + "LibreOffice",
|
||||||
|
programFiles + File.separator + "OpenOffice 4",
|
||||||
|
programFiles + File.separator + "LibreOffice 4"
|
||||||
|
);
|
||||||
|
} else if (PlatformUtils.isMac()) {
|
||||||
|
return findOfficeHome(
|
||||||
|
"/Applications/OpenOffice.org.app/Contents",
|
||||||
|
"/Applications/OpenOffice.app/Contents",
|
||||||
|
"/Applications/LibreOffice.app/Contents"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Linux or other *nix variants
|
||||||
|
return findOfficeHome(
|
||||||
|
"/opt/openoffice.org3",
|
||||||
|
"/opt/openoffice",
|
||||||
|
"/opt/libreoffice",
|
||||||
|
"/opt/libreoffice6.0",
|
||||||
|
"/opt/libreoffice6.1",
|
||||||
|
"/opt/libreoffice6.2",
|
||||||
|
"/opt/libreoffice6.3",
|
||||||
|
"/opt/libreoffice6.4",
|
||||||
|
"/opt/libreoffice7.0",
|
||||||
|
"/opt/libreoffice7.1",
|
||||||
|
"/opt/libreoffice7.2",
|
||||||
|
"/opt/openoffice4",
|
||||||
|
"/usr/lib/openoffice",
|
||||||
|
"/usr/lib/libreoffice"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File findOfficeHome(String... knownPaths) {
|
||||||
|
for (String path : knownPaths) {
|
||||||
|
File home = new File(path);
|
||||||
|
if (getOfficeExecutable(home).isFile()) {
|
||||||
|
return home;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File getOfficeExecutable(File officeHome) {
|
||||||
|
if (PlatformUtils.isMac()) {
|
||||||
|
return new File(officeHome, "MacOS/soffice");
|
||||||
|
} else {
|
||||||
|
return new File(officeHome, "program/soffice.bin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SpringBoot application.properties 支持从环境变量获取值
|
||||||
|
* @param properties
|
||||||
|
*/
|
||||||
|
public synchronized static void restorePropertiesFromEnvFormat(Properties properties) {
|
||||||
|
Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Map.Entry<Object, Object> entry = iterator.next();
|
||||||
|
String key = entry.getKey().toString();
|
||||||
|
String value = entry.getValue().toString();
|
||||||
|
if (value.trim().startsWith("${") && value.trim().endsWith("}")) {
|
||||||
|
int beginIndex = value.indexOf(":");
|
||||||
|
if (beginIndex < 0) {
|
||||||
|
beginIndex = value.length() - 1;
|
||||||
|
}
|
||||||
|
int endIndex = value.length() - 1;
|
||||||
|
String envKey = value.substring(2, beginIndex);
|
||||||
|
String envValue = System.getenv(envKey);
|
||||||
|
if (envValue == null || "".equals(envValue.trim())) {
|
||||||
|
value = value.substring(beginIndex + 1, endIndex);
|
||||||
|
} else {
|
||||||
|
value = envValue;
|
||||||
|
}
|
||||||
|
properties.setProperty(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
//
|
||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
class PooledOfficeManager implements OfficeManager {
|
||||||
|
|
||||||
|
private final PooledOfficeManagerSettings settings;
|
||||||
|
private final ManagedOfficeProcess managedOfficeProcess;
|
||||||
|
private final SuspendableThreadPoolExecutor taskExecutor;
|
||||||
|
|
||||||
|
private volatile boolean stopping = false;
|
||||||
|
private int taskCount;
|
||||||
|
private Future<?> currentTask;
|
||||||
|
|
||||||
|
private final Logger logger = Logger.getLogger(getClass().getName());
|
||||||
|
|
||||||
|
private OfficeConnectionEventListener connectionEventListener = new OfficeConnectionEventListener() {
|
||||||
|
public void connected(OfficeConnectionEvent event) {
|
||||||
|
taskCount = 0;
|
||||||
|
taskExecutor.setAvailable(true);
|
||||||
|
}
|
||||||
|
public void disconnected(OfficeConnectionEvent event) {
|
||||||
|
taskExecutor.setAvailable(false);
|
||||||
|
if (stopping) {
|
||||||
|
// expected
|
||||||
|
stopping = false;
|
||||||
|
} else {
|
||||||
|
logger.warning("connection lost unexpectedly; attempting restart");
|
||||||
|
if (currentTask != null) {
|
||||||
|
currentTask.cancel(true);
|
||||||
|
}
|
||||||
|
managedOfficeProcess.restartDueToLostConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public PooledOfficeManager(UnoUrl unoUrl) {
|
||||||
|
this(new PooledOfficeManagerSettings(unoUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PooledOfficeManager(PooledOfficeManagerSettings settings) {
|
||||||
|
this.settings = settings;
|
||||||
|
managedOfficeProcess = new ManagedOfficeProcess(settings);
|
||||||
|
managedOfficeProcess.getConnection().addConnectionEventListener(connectionEventListener);
|
||||||
|
taskExecutor = new SuspendableThreadPoolExecutor(new NamedThreadFactory("OfficeTaskThread"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(final OfficeTask task) throws OfficeException {
|
||||||
|
Future<?> futureTask = taskExecutor.submit(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (settings.getMaxTasksPerProcess() > 0 && ++taskCount == settings.getMaxTasksPerProcess() + 1) {
|
||||||
|
logger.info(String.format("reached limit of %d maxTasksPerProcess: restarting", settings.getMaxTasksPerProcess()));
|
||||||
|
taskExecutor.setAvailable(false);
|
||||||
|
stopping = true;
|
||||||
|
managedOfficeProcess.restartAndWait();
|
||||||
|
//FIXME taskCount will be 0 rather than 1 at this point
|
||||||
|
}
|
||||||
|
task.execute(managedOfficeProcess.getConnection());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
currentTask = futureTask;
|
||||||
|
try {
|
||||||
|
futureTask.get(settings.getTaskExecutionTimeout(), TimeUnit.MILLISECONDS);
|
||||||
|
} catch (TimeoutException timeoutException) {
|
||||||
|
managedOfficeProcess.restartDueToTaskTimeout();
|
||||||
|
throw new OfficeException("task did not complete within timeout", timeoutException);
|
||||||
|
} catch (ExecutionException executionException) {
|
||||||
|
if (executionException.getCause() instanceof OfficeException) {
|
||||||
|
throw (OfficeException) executionException.getCause();
|
||||||
|
} else {
|
||||||
|
throw new OfficeException("task failed", executionException.getCause());
|
||||||
|
}
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new OfficeException("task failed", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() throws OfficeException {
|
||||||
|
managedOfficeProcess.startAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() throws OfficeException {
|
||||||
|
taskExecutor.setAvailable(false);
|
||||||
|
stopping = true;
|
||||||
|
taskExecutor.shutdownNow();
|
||||||
|
managedOfficeProcess.stopAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning() {
|
||||||
|
return managedOfficeProcess.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
class PooledOfficeManagerSettings extends ManagedOfficeProcessSettings {
|
||||||
|
|
||||||
|
public static final long DEFAULT_TASK_EXECUTION_TIMEOUT = 120000L;
|
||||||
|
public static final int DEFAULT_MAX_TASKS_PER_PROCESS = 200;
|
||||||
|
|
||||||
|
private long taskExecutionTimeout = DEFAULT_TASK_EXECUTION_TIMEOUT;
|
||||||
|
private int maxTasksPerProcess = DEFAULT_MAX_TASKS_PER_PROCESS;
|
||||||
|
|
||||||
|
public PooledOfficeManagerSettings(UnoUrl unoUrl) {
|
||||||
|
super(unoUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTaskExecutionTimeout() {
|
||||||
|
return taskExecutionTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTaskExecutionTimeout(long taskExecutionTimeout) {
|
||||||
|
this.taskExecutionTimeout = taskExecutionTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxTasksPerProcess() {
|
||||||
|
return maxTasksPerProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxTasksPerProcess(int maxTasksPerProcess) {
|
||||||
|
this.maxTasksPerProcess = maxTasksPerProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.artofsolving.jodconverter.process.ProcessManager;
|
||||||
|
|
||||||
|
class ProcessPoolOfficeManager implements OfficeManager {
|
||||||
|
|
||||||
|
private final BlockingQueue<PooledOfficeManager> pool;
|
||||||
|
private final PooledOfficeManager[] pooledManagers;
|
||||||
|
private final long taskQueueTimeout;
|
||||||
|
|
||||||
|
private volatile boolean running = false;
|
||||||
|
|
||||||
|
private final Logger logger = Logger.getLogger(ProcessPoolOfficeManager.class.getName());
|
||||||
|
|
||||||
|
public ProcessPoolOfficeManager(File officeHome, UnoUrl[] unoUrls, String[] runAsArgs, File templateProfileDir, File workDir,
|
||||||
|
long retryTimeout, long taskQueueTimeout, long taskExecutionTimeout, int maxTasksPerProcess,
|
||||||
|
ProcessManager processManager) {
|
||||||
|
this.taskQueueTimeout = taskQueueTimeout;
|
||||||
|
pool = new ArrayBlockingQueue<PooledOfficeManager>(unoUrls.length);
|
||||||
|
pooledManagers = new PooledOfficeManager[unoUrls.length];
|
||||||
|
for (int i = 0; i < unoUrls.length; i++) {
|
||||||
|
PooledOfficeManagerSettings settings = new PooledOfficeManagerSettings(unoUrls[i]);
|
||||||
|
settings.setRunAsArgs(runAsArgs);
|
||||||
|
settings.setTemplateProfileDir(templateProfileDir);
|
||||||
|
settings.setWorkDir(workDir);
|
||||||
|
settings.setOfficeHome(officeHome);
|
||||||
|
settings.setRetryTimeout(retryTimeout);
|
||||||
|
settings.setTaskExecutionTimeout(taskExecutionTimeout);
|
||||||
|
settings.setMaxTasksPerProcess(maxTasksPerProcess);
|
||||||
|
settings.setProcessManager(processManager);
|
||||||
|
pooledManagers[i] = new PooledOfficeManager(settings);
|
||||||
|
}
|
||||||
|
logger.info("ProcessManager implementation is " + processManager.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void start() throws OfficeException {
|
||||||
|
for (int i = 0; i < pooledManagers.length; i++) {
|
||||||
|
pooledManagers[i].start();
|
||||||
|
releaseManager(pooledManagers[i]);
|
||||||
|
}
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(OfficeTask task) throws IllegalStateException, OfficeException {
|
||||||
|
if (!running) {
|
||||||
|
throw new IllegalStateException("this OfficeManager is currently stopped");
|
||||||
|
}
|
||||||
|
PooledOfficeManager manager = null;
|
||||||
|
try {
|
||||||
|
manager = acquireManager();
|
||||||
|
if (manager == null) {
|
||||||
|
throw new OfficeException("no office manager available");
|
||||||
|
}
|
||||||
|
manager.execute(task);
|
||||||
|
} finally {
|
||||||
|
if (manager != null) {
|
||||||
|
releaseManager(manager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void stop() throws OfficeException {
|
||||||
|
running = false;
|
||||||
|
logger.info("stopping");
|
||||||
|
pool.clear();
|
||||||
|
for (int i = 0; i < pooledManagers.length; i++) {
|
||||||
|
pooledManagers[i].stop();
|
||||||
|
}
|
||||||
|
logger.info("stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
private PooledOfficeManager acquireManager() {
|
||||||
|
try {
|
||||||
|
return pool.poll(taskQueueTimeout, TimeUnit.MILLISECONDS);
|
||||||
|
} catch (InterruptedException interruptedException) {
|
||||||
|
throw new OfficeException("interrupted", interruptedException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseManager(PooledOfficeManager manager) {
|
||||||
|
try {
|
||||||
|
pool.put(manager);
|
||||||
|
} catch (InterruptedException interruptedException) {
|
||||||
|
throw new OfficeException("interrupted", interruptedException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning() {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
class RetryTimeoutException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -3704437769955257514L;
|
||||||
|
|
||||||
|
public RetryTimeoutException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
abstract class Retryable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws TemporaryException for an error condition that can be temporary - i.e. retrying later could be successful
|
||||||
|
* @throws Exception for all other error conditions
|
||||||
|
*/
|
||||||
|
protected abstract void attempt() throws TemporaryException, Exception;
|
||||||
|
|
||||||
|
public void execute(long interval, long timeout) throws RetryTimeoutException, Exception {
|
||||||
|
execute(0L, interval, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(long delay, long interval, long timeout) throws RetryTimeoutException, Exception {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
if (delay > 0L) {
|
||||||
|
sleep(delay);
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
attempt();
|
||||||
|
return;
|
||||||
|
} catch (TemporaryException temporaryException) {
|
||||||
|
if (System.currentTimeMillis() - start < timeout) {
|
||||||
|
sleep(interval);
|
||||||
|
// continue
|
||||||
|
} else {
|
||||||
|
throw new RetryTimeoutException(temporaryException.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sleep(long millis) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(millis);
|
||||||
|
} catch (InterruptedException interruptedException) {
|
||||||
|
// continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.Condition;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
class SuspendableThreadPoolExecutor extends ThreadPoolExecutor {
|
||||||
|
|
||||||
|
private boolean available = false;
|
||||||
|
private ReentrantLock suspendLock = new ReentrantLock();
|
||||||
|
private Condition availableCondition = suspendLock.newCondition();
|
||||||
|
|
||||||
|
public SuspendableThreadPoolExecutor(ThreadFactory threadFactory) {
|
||||||
|
super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void beforeExecute(Thread thread, Runnable task) {
|
||||||
|
super.beforeExecute(thread, task);
|
||||||
|
suspendLock.lock();
|
||||||
|
try {
|
||||||
|
while (!available) {
|
||||||
|
availableCondition.await();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException interruptedException) {
|
||||||
|
thread.interrupt();
|
||||||
|
} finally {
|
||||||
|
suspendLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvailable(boolean available) {
|
||||||
|
suspendLock.lock();
|
||||||
|
try {
|
||||||
|
this.available = available;
|
||||||
|
if (available) {
|
||||||
|
availableCondition.signalAll();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
suspendLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an error condition that can be temporary, i.e. that could go
|
||||||
|
* away by simply retrying the same operation after an interval.
|
||||||
|
*/
|
||||||
|
class TemporaryException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 7237380113208327295L;
|
||||||
|
|
||||||
|
public TemporaryException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println(new BigDecimal("7412611111110.99"));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.office;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates the UNO Interprocess Connection type and parameters.
|
||||||
|
* <p>
|
||||||
|
* OpenOffice.org supports two connection types: TCP sockets and named pipes.
|
||||||
|
* Named pipes are marginally faster and do not take up a TCP port, but they
|
||||||
|
* require native libraries, which means setting <em>java.library.path</em>
|
||||||
|
* when starting Java. E.g. on Linux
|
||||||
|
* <pre>
|
||||||
|
* java -Djava.library.path=/opt/openoffice.org/ure/lib ...
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* See <a href="http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/ProUNO/Opening_a_Connection">Opening a Connection</a>
|
||||||
|
* in the OpenOffice.org Developer's Guide for more details.
|
||||||
|
*/
|
||||||
|
class UnoUrl {
|
||||||
|
|
||||||
|
private final String acceptString;
|
||||||
|
private final String connectString;
|
||||||
|
|
||||||
|
private UnoUrl(String acceptString, String connectString) {
|
||||||
|
this.acceptString = acceptString;
|
||||||
|
this.connectString = connectString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UnoUrl socket(int port) {
|
||||||
|
String socketString = "socket,host=127.0.0.1,port=" + port;
|
||||||
|
return new UnoUrl(socketString, socketString + ",tcpNoDelay=1");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UnoUrl pipe(String pipeName) {
|
||||||
|
String pipeString = "pipe,name=" + pipeName;
|
||||||
|
return new UnoUrl(pipeString, pipeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAcceptString() {
|
||||||
|
return acceptString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConnectString() {
|
||||||
|
return connectString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return connectString;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.process;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ProcessManager} implementation for Linux. Uses the <tt>ps</tt>
|
||||||
|
* and <tt>kill</tt> commands.
|
||||||
|
* <p>
|
||||||
|
* Should Work on Solaris too, except that the command line string
|
||||||
|
* returned by <tt>ps</tt> there is limited to 80 characters and this affects
|
||||||
|
* {@link #findPid(String)}.
|
||||||
|
*/
|
||||||
|
public class LinuxProcessManager implements ProcessManager {
|
||||||
|
|
||||||
|
private static final Pattern PS_OUTPUT_LINE = Pattern.compile("^\\s*(\\d+)\\s+(.*)$");
|
||||||
|
|
||||||
|
private String[] runAsArgs;
|
||||||
|
|
||||||
|
public void setRunAsArgs(String... runAsArgs) {
|
||||||
|
this.runAsArgs = runAsArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String[] psCommand() {
|
||||||
|
return new String[] { "/bin/ps", "-e", "-o", "pid,args" };
|
||||||
|
}
|
||||||
|
|
||||||
|
public long findPid(ProcessQuery query) throws IOException {
|
||||||
|
String regex = Pattern.quote(query.getCommand()) + ".*" + Pattern.quote(query.getArgument());
|
||||||
|
Pattern commandPattern = Pattern.compile(regex);
|
||||||
|
for (String line : execute(psCommand())) {
|
||||||
|
Matcher lineMatcher = PS_OUTPUT_LINE.matcher(line);
|
||||||
|
if (lineMatcher.matches()) {
|
||||||
|
String command = lineMatcher.group(2);
|
||||||
|
Matcher commandMatcher = commandPattern.matcher(command);
|
||||||
|
if (commandMatcher.find()) {
|
||||||
|
return Long.parseLong(lineMatcher.group(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PID_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void kill(Process process, long pid) throws IOException {
|
||||||
|
if (pid <= 0) {
|
||||||
|
throw new IllegalArgumentException("invalid pid: " + pid);
|
||||||
|
}
|
||||||
|
execute("/bin/kill", "-KILL", Long.toString(pid));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> execute(String... args) throws IOException {
|
||||||
|
String[] command;
|
||||||
|
if (runAsArgs != null) {
|
||||||
|
command = new String[runAsArgs.length + args.length];
|
||||||
|
System.arraycopy(runAsArgs, 0, command, 0, runAsArgs.length);
|
||||||
|
System.arraycopy(args, 0, command, runAsArgs.length, args.length);
|
||||||
|
} else {
|
||||||
|
command = args;
|
||||||
|
}
|
||||||
|
Process process = new ProcessBuilder(command).start();
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<String> lines = IOUtils.readLines(process.getInputStream());
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.process;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface ProcessManager {
|
||||||
|
|
||||||
|
public static final long PID_NOT_FOUND = -2;
|
||||||
|
public static final long PID_UNKNOWN = -1;
|
||||||
|
|
||||||
|
void kill(Process process, long pid) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param query
|
||||||
|
* @return the pid if found, {@link #PID_NOT_FOUND} if not,
|
||||||
|
* or {@link #PID_UNKNOWN} if this implementation is unable to find out
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
long findPid(ProcessQuery query) throws IOException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.process;
|
||||||
|
|
||||||
|
public class ProcessQuery {
|
||||||
|
|
||||||
|
private final String command;
|
||||||
|
private final String argument;
|
||||||
|
|
||||||
|
public ProcessQuery(String command, String argument) {
|
||||||
|
this.command = command;
|
||||||
|
this.argument = argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getArgument() {
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.process;
|
||||||
|
|
||||||
|
public class PureJavaProcessManager implements ProcessManager {
|
||||||
|
|
||||||
|
public long findPid(ProcessQuery query) {
|
||||||
|
return PID_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void kill(Process process, long pid) {
|
||||||
|
process.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.process;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.hyperic.sigar.Sigar;
|
||||||
|
import org.hyperic.sigar.SigarException;
|
||||||
|
import org.hyperic.sigar.ptql.ProcessFinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ProcessManager} implementation that uses the SIGAR library.
|
||||||
|
* <p>
|
||||||
|
* Requires the sigar.jar in the classpath and the appropriate system-specific
|
||||||
|
* native library (e.g. <tt>libsigar-x86-linux.so</tt> on Linux x86) available
|
||||||
|
* in the <em>java.library.path</em>.
|
||||||
|
* <p>
|
||||||
|
* See the <a href="http://support.hyperic.com/display/SIGAR">SIGAR site</a>
|
||||||
|
* for documentation and downloads.
|
||||||
|
*/
|
||||||
|
public class SigarProcessManager implements ProcessManager {
|
||||||
|
|
||||||
|
public long findPid(ProcessQuery query) throws IOException {
|
||||||
|
Sigar sigar = new Sigar();
|
||||||
|
try {
|
||||||
|
long[] pids = ProcessFinder.find(sigar, "State.Name.eq=" + query.getCommand());
|
||||||
|
for (int i = 0; i < pids.length; i++) {
|
||||||
|
String[] arguments = sigar.getProcArgs(pids[i]);
|
||||||
|
if (arguments != null && argumentMatches(arguments, query.getArgument())) {
|
||||||
|
return pids[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PID_NOT_FOUND;
|
||||||
|
} catch (SigarException sigarException) {
|
||||||
|
throw new IOException("findPid failed", sigarException);
|
||||||
|
} finally {
|
||||||
|
sigar.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void kill(Process process, long pid) throws IOException {
|
||||||
|
Sigar sigar = new Sigar();
|
||||||
|
try {
|
||||||
|
sigar.kill(pid, Sigar.getSigNum("KILL"));
|
||||||
|
} catch (SigarException sigarException) {
|
||||||
|
throw new IOException("kill failed", sigarException);
|
||||||
|
} finally {
|
||||||
|
sigar.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean argumentMatches(String[] arguments, String expected) {
|
||||||
|
for (String argument : arguments) {
|
||||||
|
if (argument.contains(expected)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package org.artofsolving.jodconverter.util;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : kl
|
||||||
|
**/
|
||||||
|
public class ConfigUtils {
|
||||||
|
|
||||||
|
private static final String MAIN_DIRECTORY_NAME = "server";
|
||||||
|
private static final String OFFICE_PLUGIN_NAME = "office-plugin";
|
||||||
|
|
||||||
|
public static String getHomePath() {
|
||||||
|
String userDir = System.getenv("KKFILEVIEW_BIN_FOLDER");
|
||||||
|
if (userDir == null) {
|
||||||
|
userDir = System.getProperty("user.dir");
|
||||||
|
}
|
||||||
|
return userDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取环境变量,如果找不到则返回默认值
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
|
private static String getEnvOrDefault(String key, String def) {
|
||||||
|
String value = System.getenv(key);
|
||||||
|
return value == null ? def : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回参数列表中第一个真实存在的路径,或者 null
|
||||||
|
private static String firstExists(File... paths) {
|
||||||
|
for (File path : paths) {
|
||||||
|
if (path.exists()) {
|
||||||
|
return path.getAbsolutePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getOfficePluginPath() {
|
||||||
|
String userDir = System.getProperty("user.dir");
|
||||||
|
String binFolder = getEnvOrDefault("KKFILEVIEW_BIN_FOLDER", userDir);
|
||||||
|
|
||||||
|
File pluginPath = new File(binFolder);
|
||||||
|
|
||||||
|
// 如果指定了 bin 或其父目录,则返回父目录
|
||||||
|
// 否则在当前目录和父目录中寻找 office-plugin
|
||||||
|
if (new File(pluginPath, "bin").exists()) {
|
||||||
|
return pluginPath.getAbsolutePath();
|
||||||
|
|
||||||
|
} else if (pluginPath.exists() && pluginPath.getName().equals("bin")) {
|
||||||
|
return pluginPath.getParentFile().getAbsolutePath();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return firstExists(
|
||||||
|
new File(pluginPath, OFFICE_PLUGIN_NAME),
|
||||||
|
new File(pluginPath.getParentFile(), OFFICE_PLUGIN_NAME)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getCustomizedConfigPath() {
|
||||||
|
String homePath = getHomePath();
|
||||||
|
String separator = java.io.File.separator;
|
||||||
|
return homePath + separator + "application.properties";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
//
|
||||||
|
// JODConverter - Java OpenDocument Converter
|
||||||
|
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||||
|
//
|
||||||
|
// JODConverter is Open Source software, you can redistribute it and/or
|
||||||
|
// modify it under either (at your option) of the following licenses
|
||||||
|
//
|
||||||
|
// 1. The GNU Lesser General Public License v3 (or later)
|
||||||
|
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// 2. The Apache License, Version 2.0
|
||||||
|
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
//
|
||||||
|
package org.artofsolving.jodconverter.util;
|
||||||
|
|
||||||
|
public class PlatformUtils {
|
||||||
|
|
||||||
|
private static final String OS_NAME = System.getProperty("os.name").toLowerCase();
|
||||||
|
|
||||||
|
private PlatformUtils() {
|
||||||
|
throw new AssertionError("utility class must not be instantiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLinux() {
|
||||||
|
return OS_NAME.startsWith("linux");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isMac() {
|
||||||
|
return OS_NAME.startsWith("mac");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isWindows() {
|
||||||
|
return OS_NAME.startsWith("windows");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
188
office-plugin/src/main/resources/document-formats.js
Normal file
188
office-plugin/src/main/resources/document-formats.js
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Portable Document Format",
|
||||||
|
"extension": "pdf",
|
||||||
|
"mediaType": "application/pdf",
|
||||||
|
"storePropertiesByFamily": {
|
||||||
|
"DRAWING": {"FilterName": "draw_pdf_Export"},
|
||||||
|
"SPREADSHEET": {"FilterName": "calc_pdf_Export"},
|
||||||
|
"PRESENTATION": {"FilterName": "impress_pdf_Export"},
|
||||||
|
"TEXT": {"FilterName": "writer_pdf_Export"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Macromedia Flash",
|
||||||
|
"extension": "swf",
|
||||||
|
"mediaType": "application/x-shockwave-flash",
|
||||||
|
"storePropertiesByFamily": {
|
||||||
|
"DRAWING": {"FilterName": "draw_flash_Export"},
|
||||||
|
"PRESENTATION": {"FilterName": "impress_flash_Export"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HTML",
|
||||||
|
"extension": "html",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"storePropertiesByFamily": {
|
||||||
|
"SPREADSHEET": {"FilterName": "HTML (StarCalc)"},
|
||||||
|
"PRESENTATION": {"FilterName": "impress_html_Export"},
|
||||||
|
"TEXT": {"FilterName": "HTML (StarWriter)"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenDocument Text",
|
||||||
|
"extension": "odt",
|
||||||
|
"mediaType": "application/vnd.oasis.opendocument.text",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"storePropertiesByFamily": {"TEXT": {"FilterName": "writer8"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenOffice.org 1.0 Text Document",
|
||||||
|
"extension": "sxw",
|
||||||
|
"mediaType": "application/vnd.sun.xml.writer",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"storePropertiesByFamily": {"TEXT": {"FilterName": "StarOffice XML (Writer)"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft Word",
|
||||||
|
"extension": "doc",
|
||||||
|
"mediaType": "application/msword",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"storePropertiesByFamily": {"TEXT": {"FilterName": "MS Word 97"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft Word 2007 XML",
|
||||||
|
"extension": "docx",
|
||||||
|
"mediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
"inputFamily": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rich Text Format",
|
||||||
|
"extension": "rtf",
|
||||||
|
"mediaType": "text/rtf",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"storePropertiesByFamily": {"TEXT": {"FilterName": "Rich Text Format"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "WordPerfect",
|
||||||
|
"extension": "wpd",
|
||||||
|
"mediaType": "application/wordperfect",
|
||||||
|
"inputFamily": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Plain Text",
|
||||||
|
"extension": "txt",
|
||||||
|
"mediaType": "text/plain",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"loadProperties": {
|
||||||
|
"FilterName": "Text (encoded)",
|
||||||
|
"FilterOptions": "utf8"
|
||||||
|
},
|
||||||
|
"storePropertiesByFamily": {"TEXT": {
|
||||||
|
"FilterName": "Text (encoded)",
|
||||||
|
"FilterOptions": "utf8"
|
||||||
|
}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MediaWiki wikitext",
|
||||||
|
"extension": "wiki",
|
||||||
|
"mediaType": "text/x-wiki",
|
||||||
|
"storePropertiesByFamily": {"TEXT": {"FilterName": "MediaWiki"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenDocument Spreadsheet",
|
||||||
|
"extension": "ods",
|
||||||
|
"mediaType": "application/vnd.oasis.opendocument.spreadsheet",
|
||||||
|
"inputFamily": "SPREADSHEET",
|
||||||
|
"storePropertiesByFamily": {"SPREADSHEET": {"FilterName": "calc8"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenOffice.org 1.0 Spreadsheet",
|
||||||
|
"extension": "sxc",
|
||||||
|
"mediaType": "application/vnd.sun.xml.calc",
|
||||||
|
"inputFamily": "SPREADSHEET",
|
||||||
|
"storePropertiesByFamily": {"SPREADSHEET": {"FilterName": "StarOffice XML (Calc)"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft Excel",
|
||||||
|
"extension": "xls",
|
||||||
|
"mediaType": "application/vnd.ms-excel",
|
||||||
|
"inputFamily": "SPREADSHEET",
|
||||||
|
"storePropertiesByFamily": {"SPREADSHEET": {"FilterName": "MS Excel 97"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft Excel 2007 XML",
|
||||||
|
"extension": "xlsx",
|
||||||
|
"mediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
"inputFamily": "SPREADSHEET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Comma Separated Values",
|
||||||
|
"extension": "csv",
|
||||||
|
"mediaType": "text/csv",
|
||||||
|
"inputFamily": "SPREADSHEET",
|
||||||
|
"loadProperties": {
|
||||||
|
"FilterName": "Text - txt - csv (StarCalc)",
|
||||||
|
"FilterOptions": "44,34,0"
|
||||||
|
},
|
||||||
|
"storePropertiesByFamily": {"SPREADSHEET": {
|
||||||
|
"FilterName": "Text - txt - csv (StarCalc)",
|
||||||
|
"FilterOptions": "44,34,0"
|
||||||
|
}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tab Separated Values",
|
||||||
|
"extension": "tsv",
|
||||||
|
"mediaType": "text/tab-separated-values",
|
||||||
|
"inputFamily": "SPREADSHEET",
|
||||||
|
"loadProperties": {
|
||||||
|
"FilterName": "Text - txt - csv (StarCalc)",
|
||||||
|
"FilterOptions": "9,34,0"
|
||||||
|
},
|
||||||
|
"storePropertiesByFamily": {"SPREADSHEET": {
|
||||||
|
"FilterName": "Text - txt - csv (StarCalc)",
|
||||||
|
"FilterOptions": "9,34,0"
|
||||||
|
}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenDocument Presentation",
|
||||||
|
"extension": "odp",
|
||||||
|
"mediaType": "application/vnd.oasis.opendocument.presentation",
|
||||||
|
"inputFamily": "PRESENTATION",
|
||||||
|
"storePropertiesByFamily": {"PRESENTATION": {"FilterName": "impress8"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenOffice.org 1.0 Presentation",
|
||||||
|
"extension": "sxi",
|
||||||
|
"mediaType": "application/vnd.sun.xml.impress",
|
||||||
|
"inputFamily": "PRESENTATION",
|
||||||
|
"storePropertiesByFamily": {"PRESENTATION": {"FilterName": "StarOffice XML (Impress)"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft PowerPoint",
|
||||||
|
"extension": "ppt",
|
||||||
|
"mediaType": "application/vnd.ms-powerpoint",
|
||||||
|
"inputFamily": "PRESENTATION",
|
||||||
|
"storePropertiesByFamily": {"PRESENTATION": {"FilterName": "MS PowerPoint 97"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft PowerPoint 2007 XML",
|
||||||
|
"extension": "pptx",
|
||||||
|
"mediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||||
|
"inputFamily": "PRESENTATION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenDocument Drawing",
|
||||||
|
"extension": "odg",
|
||||||
|
"mediaType": "application/vnd.oasis.opendocument.graphics",
|
||||||
|
"inputFamily": "DRAWING",
|
||||||
|
"storePropertiesByFamily": {"DRAWING": {"FilterName": "draw8"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Scalable Vector Graphics",
|
||||||
|
"extension": "svg",
|
||||||
|
"mediaType": "image/svg+xml",
|
||||||
|
"storePropertiesByFamily": {"DRAWING": {"FilterName": "draw_svg_Export"}}
|
||||||
|
}
|
||||||
|
]
|
188
office-plugin/target/classes/document-formats.js
Normal file
188
office-plugin/target/classes/document-formats.js
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Portable Document Format",
|
||||||
|
"extension": "pdf",
|
||||||
|
"mediaType": "application/pdf",
|
||||||
|
"storePropertiesByFamily": {
|
||||||
|
"DRAWING": {"FilterName": "draw_pdf_Export"},
|
||||||
|
"SPREADSHEET": {"FilterName": "calc_pdf_Export"},
|
||||||
|
"PRESENTATION": {"FilterName": "impress_pdf_Export"},
|
||||||
|
"TEXT": {"FilterName": "writer_pdf_Export"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Macromedia Flash",
|
||||||
|
"extension": "swf",
|
||||||
|
"mediaType": "application/x-shockwave-flash",
|
||||||
|
"storePropertiesByFamily": {
|
||||||
|
"DRAWING": {"FilterName": "draw_flash_Export"},
|
||||||
|
"PRESENTATION": {"FilterName": "impress_flash_Export"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HTML",
|
||||||
|
"extension": "html",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"storePropertiesByFamily": {
|
||||||
|
"SPREADSHEET": {"FilterName": "HTML (StarCalc)"},
|
||||||
|
"PRESENTATION": {"FilterName": "impress_html_Export"},
|
||||||
|
"TEXT": {"FilterName": "HTML (StarWriter)"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenDocument Text",
|
||||||
|
"extension": "odt",
|
||||||
|
"mediaType": "application/vnd.oasis.opendocument.text",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"storePropertiesByFamily": {"TEXT": {"FilterName": "writer8"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenOffice.org 1.0 Text Document",
|
||||||
|
"extension": "sxw",
|
||||||
|
"mediaType": "application/vnd.sun.xml.writer",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"storePropertiesByFamily": {"TEXT": {"FilterName": "StarOffice XML (Writer)"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft Word",
|
||||||
|
"extension": "doc",
|
||||||
|
"mediaType": "application/msword",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"storePropertiesByFamily": {"TEXT": {"FilterName": "MS Word 97"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft Word 2007 XML",
|
||||||
|
"extension": "docx",
|
||||||
|
"mediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
"inputFamily": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rich Text Format",
|
||||||
|
"extension": "rtf",
|
||||||
|
"mediaType": "text/rtf",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"storePropertiesByFamily": {"TEXT": {"FilterName": "Rich Text Format"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "WordPerfect",
|
||||||
|
"extension": "wpd",
|
||||||
|
"mediaType": "application/wordperfect",
|
||||||
|
"inputFamily": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Plain Text",
|
||||||
|
"extension": "txt",
|
||||||
|
"mediaType": "text/plain",
|
||||||
|
"inputFamily": "TEXT",
|
||||||
|
"loadProperties": {
|
||||||
|
"FilterName": "Text (encoded)",
|
||||||
|
"FilterOptions": "utf8"
|
||||||
|
},
|
||||||
|
"storePropertiesByFamily": {"TEXT": {
|
||||||
|
"FilterName": "Text (encoded)",
|
||||||
|
"FilterOptions": "utf8"
|
||||||
|
}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MediaWiki wikitext",
|
||||||
|
"extension": "wiki",
|
||||||
|
"mediaType": "text/x-wiki",
|
||||||
|
"storePropertiesByFamily": {"TEXT": {"FilterName": "MediaWiki"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenDocument Spreadsheet",
|
||||||
|
"extension": "ods",
|
||||||
|
"mediaType": "application/vnd.oasis.opendocument.spreadsheet",
|
||||||
|
"inputFamily": "SPREADSHEET",
|
||||||
|
"storePropertiesByFamily": {"SPREADSHEET": {"FilterName": "calc8"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenOffice.org 1.0 Spreadsheet",
|
||||||
|
"extension": "sxc",
|
||||||
|
"mediaType": "application/vnd.sun.xml.calc",
|
||||||
|
"inputFamily": "SPREADSHEET",
|
||||||
|
"storePropertiesByFamily": {"SPREADSHEET": {"FilterName": "StarOffice XML (Calc)"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft Excel",
|
||||||
|
"extension": "xls",
|
||||||
|
"mediaType": "application/vnd.ms-excel",
|
||||||
|
"inputFamily": "SPREADSHEET",
|
||||||
|
"storePropertiesByFamily": {"SPREADSHEET": {"FilterName": "MS Excel 97"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft Excel 2007 XML",
|
||||||
|
"extension": "xlsx",
|
||||||
|
"mediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
"inputFamily": "SPREADSHEET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Comma Separated Values",
|
||||||
|
"extension": "csv",
|
||||||
|
"mediaType": "text/csv",
|
||||||
|
"inputFamily": "SPREADSHEET",
|
||||||
|
"loadProperties": {
|
||||||
|
"FilterName": "Text - txt - csv (StarCalc)",
|
||||||
|
"FilterOptions": "44,34,0"
|
||||||
|
},
|
||||||
|
"storePropertiesByFamily": {"SPREADSHEET": {
|
||||||
|
"FilterName": "Text - txt - csv (StarCalc)",
|
||||||
|
"FilterOptions": "44,34,0"
|
||||||
|
}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tab Separated Values",
|
||||||
|
"extension": "tsv",
|
||||||
|
"mediaType": "text/tab-separated-values",
|
||||||
|
"inputFamily": "SPREADSHEET",
|
||||||
|
"loadProperties": {
|
||||||
|
"FilterName": "Text - txt - csv (StarCalc)",
|
||||||
|
"FilterOptions": "9,34,0"
|
||||||
|
},
|
||||||
|
"storePropertiesByFamily": {"SPREADSHEET": {
|
||||||
|
"FilterName": "Text - txt - csv (StarCalc)",
|
||||||
|
"FilterOptions": "9,34,0"
|
||||||
|
}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenDocument Presentation",
|
||||||
|
"extension": "odp",
|
||||||
|
"mediaType": "application/vnd.oasis.opendocument.presentation",
|
||||||
|
"inputFamily": "PRESENTATION",
|
||||||
|
"storePropertiesByFamily": {"PRESENTATION": {"FilterName": "impress8"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenOffice.org 1.0 Presentation",
|
||||||
|
"extension": "sxi",
|
||||||
|
"mediaType": "application/vnd.sun.xml.impress",
|
||||||
|
"inputFamily": "PRESENTATION",
|
||||||
|
"storePropertiesByFamily": {"PRESENTATION": {"FilterName": "StarOffice XML (Impress)"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft PowerPoint",
|
||||||
|
"extension": "ppt",
|
||||||
|
"mediaType": "application/vnd.ms-powerpoint",
|
||||||
|
"inputFamily": "PRESENTATION",
|
||||||
|
"storePropertiesByFamily": {"PRESENTATION": {"FilterName": "MS PowerPoint 97"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft PowerPoint 2007 XML",
|
||||||
|
"extension": "pptx",
|
||||||
|
"mediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||||
|
"inputFamily": "PRESENTATION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenDocument Drawing",
|
||||||
|
"extension": "odg",
|
||||||
|
"mediaType": "application/vnd.oasis.opendocument.graphics",
|
||||||
|
"inputFamily": "DRAWING",
|
||||||
|
"storePropertiesByFamily": {"DRAWING": {"FilterName": "draw8"}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Scalable Vector Graphics",
|
||||||
|
"extension": "svg",
|
||||||
|
"mediaType": "image/svg+xml",
|
||||||
|
"storePropertiesByFamily": {"DRAWING": {"FilterName": "draw_svg_Export"}}
|
||||||
|
}
|
||||||
|
]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user