Compare commits

..

23 Commits

Author SHA1 Message Date
kl
4a7d61a335 Fixes an issue with xmind file preview in certain deployment scenarios 2023-03-06 14:27:14 +08:00
kl
fd10df913f Update README.md 2023-03-03 21:49:38 +08:00
kl
5d39246ef5 Update README.md 2023-03-03 21:16:19 +08:00
kl
724a0124b5 Update the installation resource address (#438)
* Update documentation

* Update the installation resource address
2023-03-03 18:58:32 +08:00
kl
976e54407e Update documentation (#437) 2023-03-03 18:42:44 +08:00
kl
b7285dc93c Update README.md (#436) 2023-03-03 17:20:20 +08:00
gaoxingzaq
c0cf4fcc39 修复特殊符号的文件无法删除 (#427)
* 修复特殊符号的文件无法删除

* cad 优化

Co-authored-by: gaoxiongzaq <admin@cxcp.com>
2023-01-17 22:56:51 +08:00
gaoxingzaq
5dc543db99 修复流的方法错误 ,修复跨域脚本缺少BASE64 (#423)
* 修复office下载方法中 错误

* 更新OFD解析效果,修复禁止trace请求无效问题,其他压缩包修复

* 修复压缩包 缓存BUG

* 限制某些特殊文件上传

* 修复OFFICE文件密码检查关闭流 上传文件关闭流 检查PDF文件是否存在

* 特殊符号的支持

Co-authored-by: gaoxiongzaq <admin@cxcp.com>
2023-01-11 13:26:18 +08:00
陈精华
04401ee600 修复office文件密码判断 2022-12-28 13:52:50 +08:00
陈精华
e0cc2b6a01 修复office文件密码判断 2022-12-28 13:35:34 +08:00
陈精华
2184264831 Update README.md 2022-12-28 10:47:12 +08:00
奋斗的小果
ac3b0cb652 fix:解决内部自签证书https协议url文件无法下载的问题 (#396)
Co-authored-by: 鞠玉果 <juyg5@chinaunicom.cn>
2022-12-28 10:40:56 +08:00
gaoxingzaq
69566834ea 1,优化URL报错,2,更新OFD组件 3,美化Excel 4,文本方法关闭字节流 5,新增多种类型文件预览 (#419)
1,优化URL报错
2,更新OFD组件
3,美化Excel
4,文本方法关闭字节流
5,新增xmind、eml、epub、"obj", "3ds", "stl", "ply", "off", "3dm", "fbx", "dae", "wrl", "3mf", "ifc","glb","o3dv","gltf","stp","bim","fcstd","step","iges","brep"格式

Co-authored-by: gaoxiongzaq <admin@cxcp.com>
2022-12-28 10:17:06 +08:00
陈精华
aa66173625 svg预览修复 2022-12-19 17:52:40 +08:00
陈精华
9ceb052eb4 移除前端commonHeader.ftl中多余的依赖 2022-12-19 16:46:55 +08:00
陈精华
f52169ec27 jodconverter转换带密码office文件 2022-12-19 16:38:50 +08:00
陈精华
d761d0cc88 更新windows内置office目录名, 适配jodconverter 2022-12-19 14:45:45 +08:00
陈精华
7d3a4ebc4e 移除office-plugin, 使用新版jodconverter 2022-12-17 00:02:36 +08:00
fuzi
281a9cfbab fix:issues/414 设置contextPath后演示地址未及时更新 (#415) 2022-12-16 23:58:56 +08:00
gaoxingzaq
8c6f5bf807 文本文档加入缓存,安全修复XSS,美化404、500报错等,新增SVG格式预览,ofd优化印章渲染兼容性 (#413)
1、文本文档加入缓存
2、安全修复XSS(跨站脚本攻击)
3、美化404、500报错等
5、新增 SVG格式预览
5、ofd优化印章渲染兼容性

Co-authored-by: gaoxiongzaq <admin@cxcp.com>
2022-12-16 23:58:26 +08:00
陈精华
bb63808767 报错页面更新知识星球帮助链接 2022-12-15 11:21:43 +08:00
陈精华
96d2765d64 开启v4.2.0版本迭代 2022-12-15 10:33:23 +08:00
陈精华
492ec024c4 更新kk开源社区链接 2022-12-14 11:04:32 +08:00
12709 changed files with 363548 additions and 45275 deletions

View File

@@ -1,5 +1,5 @@
FROM keking/kkfileview-jdk:4.1.1
MAINTAINER chenjh "842761733@qq.com"
ADD server/target/kkFileView-*.tar.gz /opt/
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-4.1.0/bin
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dspring.config.location=/opt/kkFileView-4.1.0/config/application.properties","-jar","/opt/kkFileView-4.1.0/bin/kkFileView-4.1.0.jar"]
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-4.2.0-SNAPSHOT/bin
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dspring.config.location=/opt/kkFileView-4.2.0-SNAPSHOT/config/application.properties","-jar","/opt/kkFileView-4.2.0-SNAPSHOT/bin/kkFileView-4.2.0-SNAPSHOT.jar"]

281
README.cn.md Normal file
View File

@@ -0,0 +1,281 @@
# kkFileView
文档在线预览项目解决方案项目使用流行的spring boot搭建易上手和部署万能的文件预览开源项目基本支持主流文档格式预览
1. 支持 doc, docx, xls, xlsx, xlsm, ppt, pptx, csv, tsv Office 办公文档
2. 支持 wps, dps, et 等国产 WPS Office 办公文档
3. 支持 odt, ods, ots, odp, otp, six, ott, fodt, fods 等OpenOfficeLibreOffice 办公文档
4. 支持 vsd, vsdx Visio 流程图文件
5. 支持 wmf, emf Windows 系统图像文件
6. 支持 psd Photoshop 软件模型文件
7. 支持 pdf ,ofd, rtf 等文档
8. 支持 xmind 软件模型文件
9. 支持 eml, epub 文档类型文件
10. 支持 obj, 3ds, stl, ply, gltf, glb, off, 3dm, fbx, dae, wrl, 3mf, ifc, brep, step, iges, fcstd, bim 3D 模型文件
11. 支持 dwg, dxf CAD 模型文件
12. 支持 txt, xml(渲染), md(渲染), java, php, py, js, css 等所有纯文本
13. 支持 zip, rar, jar, tar, gzip, 7z 等压缩包
14. 支持 jpg, jpeg, png, gif, bmp, ico, jfif, webp 等图片预览翻转缩放镜像
15. 支持 tif, tiff 图信息模型文件
16. 支持 tga 图像格式文件
17. 支持 svg 矢量图像格式文件
18. 支持 avi, mov, wmv, mkv, 3gp, rm 等众多音视频格式文件
> 基于当前良好的架构模式支持的文件类型在进一步丰富中
### 项目特性
- 使用 spring-boot 开发预览服务搭建部署非常简便
- rest 接口提供服务跨语言跨平台特性(java,php,python,go,php....)都支持应用接入简单方便
- 抽象预览服务接口方便二次开发非常方便添加其他类型文件预览支持
- 最最重要 Apache 协议开源代码 pull 下来想干嘛就干嘛
### 官网及文档
地址[https://kkview.cn](https://kkview.cn/)
### 在线体验
> 请善待公共服务会不定时停用
地址[https://kkview.cn/preview/index](https://kkview.cn/preview/index)
### 项目文档Project documentation
1. 详细wiki文档https://gitee.com/kekingcn/file-online-preview/wikis/pages
1. 中文文档https://gitee.com/kekingcn/file-online-preview/blob/master/README.md
1. English documenthttps://gitee.com/kekingcn/file-online-preview/blob/master/README.en.md
### 联系我们加入组织
> 我们会用心回答解决大家在项目使用中的问题也请大家在提问前至少 Google baidu 珍爱生命远离无效的交流沟通
![](./doc/知识星球.png)
### 文档预览效果
#### 1. 文本预览
支持所有类型的文本文档预览 由于文本文档类型过多无法全部枚举默认开启的类型如下 txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd
文本预览效果如下
![文本预览效果如下](https://kkview.cn/img/preview/preview-text.png)
#### 2. 图片预览
支持jpgjpegpnggif等图片预览翻转缩放镜像预览效果如下
![图片预览](https://kkview.cn/img/preview/preview-image.png)
#### 3. word文档预览
支持docdocx文档预览word预览有两种模式一种是每页word转为图片预览另一种是整个word文档转成pdf再预览pdf两种模式的适用场景如下
* 图片预览word文件大前台加载整个pdf过慢
* pdf预览内网访问加载pdf快
图片预览模式预览效果如下
![word文档预览1](https://kkview.cn/img/preview/preview-doc-image.png)
pdf预览模式预览效果如下
![word文档预览2](https://kkview.cn/img/preview/preview-doc-pdf.png)
#### 4. ppt文档预览
支持pptpptx文档预览和word文档一样有两种预览模式
图片预览模式预览效果如下
![ppt文档预览1](https://kkview.cn/img/preview/preview-ppt-image.png)
pdf预览模式预览效果如下
![ppt文档预览2](https://kkview.cn/img/preview/preview-ppt-pdf.png)
#### 5. pdf文档预览
支持pdf文档预览和word文档一样有两种预览模式
图片预览模式预览效果如下
![pdf文档预览1](https://kkview.cn/img/preview/preview-pdf-image.png)
pdf预览模式预览效果如下
![pdf文档预览2](https://kkview.cn/img/preview/preview-pdf-pdf.png)
#### 6. excel文档预览
支持xlsxlsx文档预览预览效果如下
![excel文档预览](https://kkview.cn/img/preview/preview-xls.png)
#### 7. 压缩文件预览
支持zip,rar,jar,tar,gzip等压缩包预览效果如下
![压缩文件预览1](https://kkview.cn/img/preview/preview-zip.png)
可点击压缩包中的文件名直接预览文件预览效果如下
![压缩文件预览2](https://kkview.cn/img/preview/preview-zip-inner.png)
#### 8. 多媒体文件预览
理论上支持所有的视频音频文件由于无法枚举所有文件格式默认开启的类型如下
mp3,wav,mp4,flv
视频预览效果如下
![多媒体文件预览1](https://kkview.cn/img/preview/preview-video.png)
音频预览效果如下
![多媒体文件预览2](https://kkview.cn/img/preview/preview-audio.png)
#### 9. CAD文档预览
支持CAD dwg文档预览和word文档一样有两种预览模式
图片预览模式预览效果如下
![cad文档预览1](https://kkview.cn/img/preview/preview-cad-image.png)
pdf预览模式预览效果如下
![cad文档预览2](https://kkview.cn/img/preview/preview-cad-pdf.png)
考虑说明篇幅原因就不贴其他格式文件的预览效果了感兴趣的可以参考下面的实例搭建下
### 快速开始
> 项目使用技术
- spring boot [spring boot开发参考指南](http://www.kailing.pub/PdfReader/web/viewer.html?file=springboot)
- freemarker
- redisson
- jodconverter
> 依赖外部环境
- redis (可选默认不用)
- OpenOffice 或者 LibreOffice( Windows 下已内置Linux 脚本启动模式会自动安装Mac OS 下需要手动安装)
1. 第一步pull 项目 https://github.com/kekingcn/file-online-preview.git
3. 第二步运行 ServerMain main 方法服务启动后访问 http://localhost:8012/
会看到如下界面代表服务启动成功
![输入图片说明](https://gitee.com/uploads/images/2017/1213/100221_ea15202e_492218.png "屏幕截图.png")
### 历史更新记录
> 2022年12月14日v4.1.0 版本发布
1. 全新首页视觉 @wsd7747
2. tif图片预览兼容多页tif的pdf转换jpg转换以及jpg在线多页预览功能 @zhangzhen1979
3. 优化docker构建方案使用分层构建方式 @yl-yue
4. 实现基于userToken缓存加密文件 @yl-yue
5. 实现加密wordpptexcel文件预览 @yl-yue
6. Linux & Docker镜像升级LibreOffice 7.3
7. 更新OFD预览组件更新tif预览组件更新PPT水印支持
8. 大量其他升级优化 & 已知问题修复
感谢 @yl-yue @wsd7747 @zhangzhen1979 @tomhusky @shenghuadun @kischn.sun 的代码贡献
> 2021年7月6日v4.0.0 版本发布
1. 底层集成OpenOffice替换为LibreOfficeOffice文件兼容性增强预览效果提升
2. 修复压缩文件目录穿越漏洞
3. 修复PPT预览使用PDF模式无效
4. 修复PPT图片预览模式前端显示异常
5. 新增功能首页文件上传功能可通过配置实时开启或禁用
6. 优化增加Office进程关闭日志
7. 优化Windows环境下查找Office组件逻辑(内置的LibreOffice优先)
8. 优化启动Office进程改同步执行
> 2021年6月17日v3.6.0 版本发布
ofd 类型文件支持版本本次版本重要功能均由社区开发贡献感谢 @gaoxingzaq@zhangxiaoxiao9527 的代码贡献
1. 新增 ofd 类型文件预览支持ofd 是国产的类似 pdf 格式的文件
2. 新增了 ffmpeg 视频文件转码预览支持打开转码功能后理论上支持所有主流视频的预览 rmrmvbflv
3. 美化了 pptpptx 类型文件预览效果比之前版本好看太多
4. 更新了 pdfboxxstreamcommon-io 等依赖的版本
> 2021年1月28日
2020农历年最后一个版本发布主要包含了部分 UI 改进和解决了 QQ 群友 Issue 里反馈的 Bug 修复最最重要的是发个新版过个好年
1. 引入galimatias,解决不规范文件名导致文件下载异常
2. 更新index接入演示界面UI风格
3. 更新markdown文件预览UI风格
4. 更新XML文件预览UI风格调整类文本预览架构更方便扩展
5. 更新simTxT文件预览UI风格
6. 调整多图连续预览上下翻图的UI
7. 采用apache-common-io包简化所有的文件下载io操作
8. XML文件预览支持切换纯文本模式
9. 增强url base64解码失败时的提示信息
10. 修复导包错误以及图片预览 bug
11. 修复发行包运行时找不到日志目录的问题
12. 修复压缩包内多图连续预览的bug
13. 修复大小写文件类型后缀没通用匹配的问题
14. 指定Base64转码采用Apache Commons-code中的实现修复base64部分jdk版本下出现的异常
15. 修复类文本类型HTML文件预览的bug
16. 修复dwg文件预览时无法在jpg和pdf两种类型之间切换
17. escaping of dangerous characters to prevent reflected xss
18. 修复重复编码导致文档转图片预览失败的问题&编码规范
> 2020年12月27日
2020年年终大版本更新架构全面设计代码全面重构代码质量全面提升二次开发更便捷欢迎拉源码品鉴提issuepr共同建设
1. 架构模块调整,大量的代码重构代码质量提升N个等级欢迎品鉴
2. 增强XML文件预览效果新增XML文档数结构预览
3. 新增markdown文件预览支持预览支持md渲染和源文本切换支持
4. 切换底层web server为jetty解决这个issuehttps://github.com/kekingcn/kkFileView/issues/168
5. 引入cpdetector解决文件编码识别问题
6. url采用base64+urlencode双编码彻底解决各种奇葩文件名预览问题
7. 新增配置项office.preview.switch.disabled控制offic文件预览切换开关
8. 优化文本类型文件预览逻辑采用Base64传输内容避免预览时再次请求文件内容
9. office预览图片模式禁用图片放大效果达到图片和pdf预览效果一致的体验
10. 直接代码静态设置pdfbox兼容低版本jdk在IDEA中运行也不会有警告提示
11. 移除guavahutool等非必须的工具包减少代码体积
12. Office组件加载异步化提速应用启动速度最快到5秒内
13. 合理设置预览消费队列的线程数
14. 修复压缩包里文件再次预览失败的bug
15. 修复图片预览的bug
> 2020年05月20日
1. 新增支持全局水印并支持通过参数动态改变水印内容
2. 新增支持CAD文件预览
3. 新增base.url配置支持使用nginx反向代理和使用context-path
4. 支持所有配置项支持从环境变量里读取方便Docker镜像部署和集群中大规模使用
5. 支持配置限信任站点只能预览来自信任点的文件源保护预览服务不被滥用
6. 支持配置自定义缓存清理时间cron表达式
7. 全部能识别的纯文本直接预览不用再转跳下载.md .java .py等
8. 支持配置限制转换后的PDF文件下载
9. 优化maven打包配置解决 .sh 脚本可能出现换行符问题
10. 将前端所有CDN依赖放到本地方便没有外网连接的用户使用
11. 首页评论服务由搜狐畅言切换到Gitalk
12. 修复url中包含特殊字符可能会引起的预览异常
13. 修复转换文件队列addTask异常
14. 修复其他已经问题
15. 官网建设[https://kkview.cn](https://kkview.cn/)
16. 官方Docker镜像仓库建设[https://hub.docker.com/r/keking/kkfileview](https://hub.docker.com/r/keking/kkfileview)
> 2019年06月18日
1. 支持自动清理缓存及预览文件
2. 支持http/https下载流url文件预览
3. 支持FTP url文件预览
4. 加入Docker构建
> 2019年04月08日
1. 缓存及队列实现抽象提供JDK和REDIS两种实现(REDIS成为可选依赖)
2. 打包方式提供zip和tar.gz包并提供一键启动脚本
> 2018年01月19日
1. 大文件入队提前处理
1. 新增addTask文件转换入队接口
1. 采用redis队列支持kkFIleView接口和异构系统入队两种方式
> 2018年01月17日
1. 优化项目结构抽象文件预览接口更方便的加入更多的文件类型预览支持方便二次开发
1. 新增英文文档说明@幻幻Fate@汝辉贡献
1. 新增图片预览文件支持类型
1. 修复压缩包内轮播图片总是从第一张开始的问题
> 2018年01月12日
1. 新增多图片同时预览
1. 支持压缩包内图片轮番预览
> 2018年01月02日
1. 修复txt等文本编码问题导致预览乱码
1. 修复项目模块依赖引入不到的问题
1. 新增spring boot profile支持多环境配置
1. 引入pdf.js预览doc等文件支持doc标题生成pdf预览菜单支持手机端预览
### 关于引用
ofd 引用于 [ofdview ](https://gitee.com/cnofd/ofdview ) 开源协议 Apache-2.0
CAD 引用于 aspose-cad 测试版本 商用请自行购买
xmind 引用于 [ xmind-embed-viewer](https://github.com/xmindltd/xmind-embed-viewer) 开源协议 MIT
epub 引用于 [ epub.js](https://github.com/futurepress/epub.js) 开源协议 BSD许可证
压缩包 引用于 [sevenzipjbinding](https://github.com/borisbrodski/sevenzipjbinding )开源协议LGPL
3D 引用于 [Online3DViewer](https://github.com/kovacsv/Online3DViewer )开源协议MIT
### 使用登记
如果这个项目解决了你的实际问题可在 https://gitee.com/kekingcn/file-online-preview/issues/IGSBV
登记下如果节省了你的三方预览服务费用也愿意支持下的话可点击下方捐助请作者喝杯咖啡也是非常感谢
### Stars 趋势图
#### Gitee
[![Stargazers over time](https://whnb.wang/img/kekingcn/file-online-preview)](https://whnb.wang/kekingcn/file-online-preview?e=86400)
#### GitHub
[![Stargazers over time](https://starchart.cc/kekingcn/kkFileView.svg)](https://starchart.cc/kekingcn/kkFileView)
### 鸣谢
- 本项目诞生于[凯京集团]在取得公司高层同意后以 Apache 协议开源出来反哺社区在此特别感谢凯京集团以及集团领导@唐老大的支持@端木详笑的贡献
- 本项目已脱离公司由[KK开源社区]维护发展壮大感谢所有给 kkFileView Issue Pr 开发者
- 本项目引入的第三方组件已在 '关于引用' 列表列出感谢这些项目 kkFileView 更出色

View File

@@ -1,166 +0,0 @@
# kkFileView
[![GitHub license](https://img.shields.io/github/license/kekingcn/kkFileView.svg?style=flat-square)](https://github.com/kekingcn/kkFileView/blob/master/LICENSE)
### Introduction
This kekingcn kkFileView project is intended to be a solution for previewing documents online. At present,there are some similar paid products in the industry.
Such as [永中office](http://dcs.yozosoft.com/)】,【[office365](http://www.officeweb365.com/)】,【[idocv](https://www.idocv.com/)】, etc...
It is an open source implementation and released under the Apache License version 2.0. Finally,It is aimed to feedback the community after obtaining the consent of company executives,
special thanks to the supports of @唐老大 and the contributions of @端木详笑.
### Features
- Build with the popular frame spring boot
- Easy to build and deploy
- Basically support online preview of mainstream office documents, such as Doc, docx, Excel, PDF, TXT, zip, rar, pictures, etc
- REST API
- Abstract file preview interface so that it is easy to extend more file extensions and develop this project on your own
### Official website and DOCS
URL[https://kkfileview.keking.cn](https://kkfileview.keking.cn)
### Live demo
> Please treat public service kindly, or this would stop at any time.
URL[https://file.keking.cn](https://file.keking.cn)
### Documentation
1. Full wiki documenthttps://gitee.com/kekingcn/file-online-preview/wikis/pages
1. 中文文档https://gitee.com/kekingcn/file-online-preview/blob/master/README.md
1. English documenthttps://gitee.com/kekingcn/file-online-preview/blob/master/README.en.md
### Contact us && Join us
> We will answer everyone's questions in use of this project.
And please Google or Baidu first before asking a question, so that we can solve it efficiently.
Cherish life away from ineffective communication.
![输入图片说明](https://gitee.com/uploads/images/2017/1219/173717_934cb068_492218.png "屏幕截图.png")
QQ group613025121
### Pictures for some samples
#### 1. Text Preview
It supports preview of all types of text documents. Because there are too many types of text documents, it is impossible to enumerate them. The default open types are as follows: txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd
The text preview effect is as follows
![text](https://kkfileview.keking.cn/img/preview/preview-text.png)
#### 2. Picture preview
Support jpg, jpeg, png, gif and other picture previews (flip, zoom, mirror). The preview effect is as follows
![image](https://kkfileview.keking.cn/img/preview/preview-image.png)
#### 3. Word document preview
Doc and docx document previews are supported. There are two modes of word previews: one is that each page of word is converted to picture previews, the other is that the whole word document is converted to PDF, and then previews PDF. The applicable scenarios of the two modes are as follows
* Picture preview modes: the word file is large, and the whole PDF loaded in the foreground is too slow
* Pdf Preview modes: intranet access, loading PDF fast
The preview effect of picture preview mode is as follows
![word1](https://kkfileview.keking.cn/img/preview/preview-doc-image.png)
The preview effect of PDF preview mode is as follows
![word2](https://kkfileview.keking.cn/img/preview/preview-doc-pdf.png)
#### 4. PPT document preview
ppt and pptx document preview are supported. Like word documents, there are two preview modes
The preview effect of picture preview mode is as follows
![ppt1](https://kkfileview.keking.cn/img/preview/preview-ppt-image.png)
The preview effect of PDF preview mode is as follows
![ppt2](https://kkfileview.keking.cn/img/preview/preview-ppt-pdf.png)
#### 5. PDF document preview
Pdf document preview is supported. Like word document, there are two preview modes
The preview effect of picture preview mode is as follows
![pdf1](https://kkfileview.keking.cn/img/preview/preview-pdf-image.png)
The preview effect of PDF preview mode is as follows
![pdf2](https://kkfileview.keking.cn/img/preview/preview-pdf-pdf.png)
#### 6. EXCEL document preview
Support XLS, xlsx document preview, the preview effect is as follows
![excel](https://kkfileview.keking.cn/img/preview/preview-xls.png)
#### 7. Compressed file Preview
Support zip, rar, jar, tar, gzip and other compressed packages. The preview effect is as follows
![compress1](https://kkfileview.keking.cn/img/preview/preview-zip.png)
Click the file name in the compressed package to preview the file directly. The preview effect is as follows
![compress2](https://kkfileview.keking.cn/img/preview/preview-zip-inner.png)
#### 8. Multimedia file Preview
Theoretically, all video and audio files are supported. Since all file formats cannot be enumerated, the default open type is as follows
mp3,wav,mp4,flv
The video preview effect is as follows
![media1](https://kkfileview.keking.cn/img/preview/preview-video.png)
The audio preview effect is as follows
![media2](https://kkfileview.keking.cn/img/preview/preview-audio.png)
#### 9. CAD document preview
CAD DWG document preview is supported. Like word document, there are two preview modes
The preview effect of Picture preview mode is as follows
![cad1](https://kkfileview.keking.cn/img/preview/preview-cad-image.png)
The preview effect of PDF preview mode is as follows
![cad2](https://kkfileview.keking.cn/img/preview/preview-cad-pdf.png)
Considering space issues, the pictures of other types of documents will not be shown here.You can deploy it by yourself if you are interested in our project.There is a way to deploy it as below.
### Quick Start
> Technology stack
- Spring boot [spring boot Development Reference Guide](http://www.kailing.pub/PdfReader/web/viewer.html?file=springboot)
- Freemarker
- Redisson
- Jodconverter
> Dependencies
- Redis(Optional, Unnecessary by default)
- OpenOffice or LibreOffice(Integrated on Windows, will be installed automatically on Linux, need to be manually installed on Mac OS)
1. First step`git pull https://github.com/kekingcn/file-online-preview.git`
2. Third stepRun the main method of FilePreviewApplication.java.After starting,visit `http://localhost:8012/`.
If everything is ok,you will see the picture below.
![输入图片说明](https://gitee.com/uploads/images/2017/1213/100221_ea15202e_492218.png "屏幕截图.png")
### Changelog
> May 20th 2020
1. Support for global watermark and dynamic change of watermark content through parameters
2. Support for CAD file Preview
3. Add configuration item base.url, support using nginx reverse proxy and set context-path
4. All configuration items can be read from environment variables, which is convenient for docker image deployment and large-scale use in cluster
5. Support the configuration of TrustHost (only the file source from the trust site can be previewed), and protect the preview service from abuse
6. Support configuration of customize cache cleanup time (cron expression)
7. All recognizable plain text can be previewed directly without downloading, such as .md .java .py, etc
8. Support configuration to limit PDF file download after conversion
9. Optimize Maven packaging configuration to solve the problem of line break in .sh script
10. Place all CDN dependencies on the front end locally for users without external network connection
11. Comment Service on home page switched from Sohu ChangYan to gitalk
12. Fixed preview exceptions that may be caused by special characters in the URL
13. Fixed the addtask exception of the transformation file queue
14. Fixed other known issues
15. Official website build: [https://kkfileview.keking.cn](https://kkfileview.keking.cn)
16. Official docker image repository build: [https://hub.docker.com/r/keking/kkfileview](https://hub.docker.com/r/keking/kkfileview)
> June 18th 2019
1. Support automatic cleaning of cache and preview files
2. Support http/https stream url file preview
3. Support FTP url file preview
4. Add Docker build
> April 8th 2019
1. Cache and queue implementations abstract, providing JDK and REDIS implementations (REDIS becomes optional dependencies)
2. Provides zip and tar.gz packages, and provides a one-click startup script
> January 17th 2018
1. Refined the project directory, abstract file preview interface, Easy to extend more file extensions and depoly this project on your own
1. Added English documentation (@幻幻Fate@汝辉) contribution
1. Support for more image file extensions
1. Fixed the issue that image carousel in zip file will always start from the first
> January 12th 2018
1. Support for multiple images preview
1. Support for images rotation preview in rar/zip
> January 2nd 2018
1. Fixed gibberish issue when preview a txt document caused by the file encoding problem
1. Fixed the issue that some module dependencies can not be found
1. Add a spring boot profile, and support for Multi-environment configuration
1. Add `pdf.js` to preview the documents such as doc,etc.,support for generating doc headlines as pdf menusupport for mobile preview
### Register Usage
If this project is helpful for you, please register on 'https://gitee.com/kekingcn/file-online-preview/issues/IGSBV',
If this project helps you to economize the service charge for preview of documents, as well as you are willing to support us, click donate below to donate a cup of coffee, we would appreciate it.

360
README.md
View File

@@ -1,251 +1,181 @@
# kkFileView
此项目为文件文档在线预览项目解决方案对标业内付费产品有[永中office](http://dcs.yozosoft.com/)】【[office365](http://www.officeweb365.com/)】【[idocv](https://www.idocv.com/)】等在取得公司高层同意后以Apache协议开源出来反哺社区在此特别感谢@唐老大的支持以及@端木详笑的贡献。该项目使用流行的spring boot搭建易上手和部署基本支持主流办公文档的在线预览如doc,docx,Excel,pdf,txt,zip,rar,图片等等
### 项目特性
1. 支持 office, pdf, cad 等办公文档
1. 支持 txt, xml(渲染), md(渲染), java, php, py, js, css 等所有纯文本
1. 支持 zip, rar, jar, tar, gzip 等压缩包
1. 支持 jpg, jpeg, png, gif, tif, tiff 等图片预览翻转缩放镜像
1. 使用 spring-boot 开发预览服务搭建部署非常简便
1. rest 接口提供服务跨语言跨平台特性(java,php,python,go,php....)都支持应用接入简单方便
1. 抽象预览服务接口方便二次开发非常方便添加其他类型文件预览支持
1. 最最重要 Apache 协议开源代码 pull 下来想干嘛就干嘛
### Introduction
### 官网及文档
Document online preview project solution, built using the popular Spring Boot framework for easy setup and deployment. This versatile open source project provides basic support for a wide range of document formats, including:
地址[https://kkfileview.keking.cn](https://kkfileview.keking.cn)
1. Supports Office documents such as `doc`, `docx`, `xls`, `xlsx`, `xlsm`, `ppt`, `pptx`, `csv`, `tsv`, etc.
2. Supports domestic WPS Office documents such as `wps`, `dps`, et.
3. Supports OpenOffice, LibreOffice office documents such as `odt`, `ods`, `ots`, `odp`, `otp`, `six`, `ott`, `fodt` and `fods`.
4. Supports Visio flowchart files such as `vsd`, `vsdx`.
5. Supports Windows system image files such as `wmf`, `emf`.
6. Supports Photoshop software model files such as `psd`.
7. Supports document formats like `pdf`, `ofd`, and `rtf`.
8. Supports software model files like `xmind`.
9. Supports document type files such as `eml`, `epub`.
10. Supports 3D model files like `obj`, `3ds`, `stl`, `ply`, `gltf`, `glb`, `off`, `3dm`, `fbx`, `dae`, `wrl`, `3mf`, `ifc`, `brep`, `step`, `iges`, `fcstd`, `bim`, etc.
11. Supports CAD model files such as `dwg`, `dxf`.
12. Supports all plain text files such as `txt`, `xml` (rendering), `md` (rendering), `java`, `php`, `py`, `js`, `css`, etc.
13. Supports compressed packages such as `zip`, `rar`, `jar`, `tar`, `gzip`, `7z`, etc.
14. Supports image previewing (flip, zoom, mirror) of `jpg`, `jpeg`, `png`, `gif`, `bmp`, `ico`, `jfif`, `webp`, etc.
15. Supports image information model files such as `tif` and `tiff`.
16. Supports image format files such as `tga`.
17. Supports vector image format files such as `svg`.
18. Supports many audio and video format files such as `avi`, `mov`, `wmv`, `mkv`, `3gp`, and `rm`.
### 在线体验
> 请善待公共服务会不定时停用
### Features
- Build with the popular frame spring boot
- Easy to build and deploy
- Basically support online preview of mainstream office documents, such as Doc, docx, Excel, PDF, TXT, zip, rar, pictures, etc
- REST API
- Abstract file preview interface so that it is easy to extend more file extensions and develop this project on your own
地址[https://file.keking.cn](https://file.keking.cn)
### Official website and DOCS
### 项目文档Project documentation
1. 详细wiki文档https://gitee.com/kekingcn/file-online-preview/wikis/pages
1. 中文文档https://gitee.com/kekingcn/file-online-preview/blob/master/README.md
1. English documenthttps://gitee.com/kekingcn/file-online-preview/blob/master/README.en.md
URL[https://kkview.cn](https://kkview.cn/)
### 联系我们加入组织
> 我们会用心回答解决大家在项目使用中的问题也请大家在提问前至少 Google baidu 珍爱生命远离无效的交流沟通
### Live demo
> Please treat public service kindly, or this would stop at any time.
![](./doc/KK开源技术交流2群群聊二维码.png)
URL[https://kkview.cn/preview/index](https://kkview.cn/preview/index)
QQ群号~~613025121(已满)~~ 2群484680571
### Quick Start
> Technology stack
- Spring boot [spring boot Development Reference Guide](http://www.kailing.pub/PdfReader/web/viewer.html?file=springboot)
- Freemarker
- Redisson
- Jodconverter
> Dependencies
- Redis(Optional, Unnecessary by default)
- OpenOffice or LibreOffice(Integrated on Windows, will be installed automatically on Linux, need to be manually installed on Mac OS)
### 文档预览效果
#### 1. 文本预览
支持所有类型的文本文档预览 由于文本文档类型过多无法全部枚举默认开启的类型如下 txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd
文本预览效果如下
![文本预览效果如下](https://kkfileview.keking.cn/img/preview/preview-text.png)
1. First step`git pull https://github.com/kekingcn/kkFileView.git`
#### 2. 图片预览
支持jpgjpegpnggif等图片预览翻转缩放镜像预览效果如下
![图片预览](https://kkfileview.keking.cn/img/preview/preview-image.png)
2. second stepRun the main method of `/server/src/main/java/cn/keking/ServerMain.java`. After starting,visit `http://localhost:8012/`.
#### 3. word文档预览
支持docdocx文档预览word预览有两种模式一种是每页word转为图片预览另一种是整个word文档转成pdf再预览pdf两种模式的适用场景如下
* 图片预览word文件大前台加载整个pdf过慢
* pdf预览内网访问加载pdf快
图片预览模式预览效果如下
![word文档预览1](https://kkfileview.keking.cn/img/preview/preview-doc-image.png)
pdf预览模式预览效果如下
![word文档预览2](https://kkfileview.keking.cn/img/preview/preview-doc-pdf.png)
### Changelog
> December 14, 2022, version 4.1.0 released:
#### 4. ppt文档预览
支持pptpptx文档预览和word文档一样有两种预览模式
图片预览模式预览效果如下
![ppt文档预览1](https://kkfileview.keking.cn/img/preview/preview-ppt-image.png)
pdf预览模式预览效果如下
![ppt文档预览2](https://kkfileview.keking.cn/img/preview/preview-ppt-pdf.png)
1. Updated homepage design by @wsd7747.
2. Compatible with multipage tif for pdf and jpg conversion and multiple page online preview for tif image preview by @zhangzhen1979.
3. Optimized docker build, using layered build method by @yl-yue.
4. Implemented file encryption based on userToken cache by @yl-yue.
5. Implemented preview for encrypted Word, PPT, and Excel files by @yl-yue.
6. Upgraded Linux & Docker images to LibreOffice 7.3.
7. Updated OFD preview component, tif preview component, and added support for PPT watermarking.
8. Numerous other upgrades, optimizations, and bug fixes.
We thank @yl-yue, @wsd7747, @zhangzhen1979, @tomhusky, @shenghuadun, and @kischn.sun for their code contributions.
#### 5. pdf文档预览
支持pdf文档预览和word文档一样有两种预览模式
图片预览模式预览效果如下
![pdf文档预览1](https://kkfileview.keking.cn/img/preview/preview-pdf-image.png)
pdf预览模式预览效果如下
![pdf文档预览2](https://kkfileview.keking.cn/img/preview/preview-pdf-pdf.png)
#### 6. excel文档预览
支持xlsxlsx文档预览预览效果如下
![excel文档预览](https://kkfileview.keking.cn/img/preview/preview-xls.png)
> July 6, 2021, version 4.0.0 released:
#### 7. 压缩文件预览
支持zip,rar,jar,tar,gzip等压缩包预览效果如下
![压缩文件预览1](https://kkfileview.keking.cn/img/preview/preview-zip.png)
可点击压缩包中的文件名直接预览文件预览效果如下
![压缩文件预览2](https://kkfileview.keking.cn/img/preview/preview-zip-inner.png)
1. The integration of OpenOffice in the underlying system has been replaced with LibreOffice, resulting in enhanced compatibility and improved preview effects for Office files.
2. Fixed the directory traversal vulnerability in compressed files.
3. Fixed the issue where previewing PPT files in PDF mode was ineffective.
4. Fixed the issue where the front-end display of image preview mode for PPT files was abnormal.
5. Added a new feature: the file upload function on the homepage can be enabled or disabled in real-time through configuration.
6. Optimized the logging of Office process shutdown.
7. Optimized the logic for finding Office components in Windows environment, with built-in LibreOffice taking priority.
8. Optimized the synchronous execution of starting Office processes.
#### 8. 多媒体文件预览
理论上支持所有的视频音频文件由于无法枚举所有文件格式默认开启的类型如下
mp3,wav,mp4,flv
视频预览效果如下
![多媒体文件预览1](https://kkfileview.keking.cn/img/preview/preview-video.png)
音频预览效果如下
![多媒体文件预览2](https://kkfileview.keking.cn/img/preview/preview-audio.png)
> June 17, 2021, version 3.6.0 released:
#### 9. CAD文档预览
支持CAD dwg文档预览和word文档一样有两种预览模式
图片预览模式预览效果如下
![cad文档预览1](https://kkfileview.keking.cn/img/preview/preview-cad-image.png)
pdf预览模式预览效果如下
![cad文档预览2](https://kkfileview.keking.cn/img/preview/preview-cad-pdf.png)
考虑说明篇幅原因就不贴其他格式文件的预览效果了感兴趣的可以参考下面的实例搭建下
This version includes support for OFD file type versions, and all the important features in this release were contributed by the community. We thank @gaoxingzaq and @zhangxiaoxiao9527 for their code contributions.
### 快速开始
> 项目使用技术
- spring boot [spring boot开发参考指南](http://www.kailing.pub/PdfReader/web/viewer.html?file=springboot)
- freemarker
- redisson
- jodconverter
> 依赖外部环境
- redis (可选默认不用)
- OpenOffice 或者 LibreOffice( Windows 下已内置Linux 脚本启动模式会自动安装Mac OS 下需要手动安装)
1. Added support for previewing OFD type files. OFD is a domestically produced file format similar to PDF.
2. Added support for transcoding and previewing video files through ffmpeg. With transcoding enabled, theoretically, all mainstream video file formats such as RM, RMVB, FLV, etc. are supported for preview.
3. Beautified the preview effect of PPT and PPTX file types, much better looking than the previous version.
4. Updated the versions of dependencies such as pdfbox, xstream, common-io.
1. 第一步pull 项目 https://github.com/kekingcn/file-online-preview.git
> January 28, 2021:
3. 第二步运行 ServerMain main 方法服务启动后访问 http://localhost:8012/
会看到如下界面代表服务启动成功
![输入图片说明](https://gitee.com/uploads/images/2017/1213/100221_ea15202e_492218.png "屏幕截图.png")
The final update of the Lunar New Year 2020 has been released, mainly including some UI improvements, bug fixes reported by QQ group users and issues, and most importantly, it is a new version for a good year.
### 历史更新记录
1. Introduced galimatias to solve the problem of abnormal file download caused by non-standard file names.
2. Updated UI style of index access demonstration interface.
3. Updated UI style of markdown file preview.
4. Updated UI style of XML file preview, adjusted the architecture of text file preview to facilitate expansion.
5. Updated UI style of simTxT file preview.
6. Adjusted the UI of continuous preview of multiple images to flip up and down.
7. Simplified all file download IO operations by adopting the apache-common-io package.
8. XML file preview supports switching to pure text mode.
9. Enhanced prompt information when url base64 decoding fails.
10. Fixed import errors and image preview bug.
11. Fixed the problem of missing log directory when running the release package.
12. Fixed the bug of continuous preview of multiple images in the compressed package.
13. Fixed the problem of no universal matching for file type suffixes in uppercase and lowercase.
14. Specified the use of the Apache Commons-code implementation for Base64 encoding to fix exceptions occurring in some JDK versions.
15. Fixed the bug of HTML file preview of text-like files.
16. Fixed the problem of inability to switch between jpg and pdf when previewing dwg files.
17. Escaped dangerous characters to prevent reflected xss.
18. Fixed the problem of duplicate encoding causing the failure of document-to-image preview and standardized the encoding.
> 2022年12月14日v4.1.0 版本发布
> December 27, 2020:
1. 全新首页视觉 @wsd7747
2. tif图片预览兼容多页tif的pdf转换jpg转换以及jpg在线多页预览功能 @zhangzhen1979
3. 优化docker构建方案使用分层构建方式 @yl-yue
4. 实现基于userToken缓存加密文件 @yl-yue
5. 实现加密wordpptexcel文件预览 @yl-yue
6. Linux & Docker镜像升级LibreOffice 7.3
7. 更新OFD预览组件更新tif预览组件更新PPT水印支持
8. 大量其他升级优化 & 已知问题修复
The year-end major update of 2020 includes comprehensive architecture design, complete code refactoring, significant improvement in code quality, and more convenient secondary development. We welcome you to review the source code and contribute to building by raising issues and pull requests.
感谢 @yl-yue @wsd7747 @zhangzhen1979 @tomhusky @shenghuadun @kischn.sun 的代码贡献
1. Adjusted architecture modules, extensively refactored code, and improved code quality by several levels. Please feel free to review.
2. Enhanced XML file preview effect and added preview of XML document structure.
3. Added support for markdown file preview, including support for md rendering and switching between source text and preview.
4. Switched the underlying web server to jetty, resolving the issue: https://github.com/kekingcn/kkFileView/issues/168
5. Introduced cpdetector to solve the problem of file encoding recognition.
6. Adopted double encoding with base64 and urlencode for URLs to completely solve preview problems with bizarre file names.
7. Added configuration item office.preview.switch.disabled to control the switch of office file preview.
8. Optimized text file preview logic, transmitting content through Base64 to avoid requesting file content again during preview.
9. Disabled the image zoom effect in office preview mode to achieve consistent experience with image and pdf preview.
10. Directly set pdfbox to be compatible with lower version JDK, and there will be no warning prompts even when run in IDEA.
11. Removed non-essential toolkits like Guava and Hutool to reduce code volume.
12. Asynchronous loading of Office components speeds up application launch to within 5 seconds.
13. Reasonable settings of the number of threads in the preview consumption queue.
14. Fixed the bug where files in compressed packages failed to preview again.
15. Fixed the bug in image preview.
> 2021年7月6日v4.0.0 版本发布
> May 20th 2020
1. Support for global watermark and dynamic change of watermark content through parameters
2. Support for CAD file Preview
3. Add configuration item base.url, support using nginx reverse proxy and set context-path
4. All configuration items can be read from environment variables, which is convenient for docker image deployment and large-scale use in cluster
5. Support the configuration of TrustHost (only the file source from the trust site can be previewed), and protect the preview service from abuse
6. Support configuration of customize cache cleanup time (cron expression)
7. All recognizable plain text can be previewed directly without downloading, such as .md .java .py, etc
8. Support configuration to limit PDF file download after conversion
9. Optimize Maven packaging configuration to solve the problem of line break in .sh script
10. Place all CDN dependencies on the front end locally for users without external network connection
11. Comment Service on home page switched from Sohu ChangYan to gitalk
12. Fixed preview exceptions that may be caused by special characters in the URL
13. Fixed the addtask exception of the transformation file queue
14. Fixed other known issues
15. Official website build: [https://kkview.cn](https://kkview.cn)
16. Official docker image repository build: [https://hub.docker.com/r/keking/kkfileview](https://hub.docker.com/r/keking/kkfileview)
1. 底层集成OpenOffice替换为LibreOfficeOffice文件兼容性增强预览效果提升
2. 修复压缩文件目录穿越漏洞
3. 修复PPT预览使用PDF模式无效
4. 修复PPT图片预览模式前端显示异常
5. 新增功能首页文件上传功能可通过配置实时开启或禁用
6. 优化增加Office进程关闭日志
7. 优化Windows环境下查找Office组件逻辑(内置的LibreOffice优先)
8. 优化启动Office进程改同步执行
> June 18th 2019
1. Support automatic cleaning of cache and preview files
2. Support http/https stream url file preview
3. Support FTP url file preview
4. Add Docker build
> 2021年6月17日v3.6.0 版本发布
> April 8th 2019
1. Cache and queue implementations abstract, providing JDK and REDIS implementations (REDIS becomes optional dependencies)
2. Provides zip and tar.gz packages, and provides a one-click startup script
ofd 类型文件支持版本本次版本重要功能均由社区开发贡献感谢 @gaoxingzaq@zhangxiaoxiao9527 的代码贡献
1. 新增 ofd 类型文件预览支持ofd 是国产的类似 pdf 格式的文件
2. 新增了 ffmpeg 视频文件转码预览支持打开转码功能后理论上支持所有主流视频的预览 rmrmvbflv
3. 美化了 pptpptx 类型文件预览效果比之前版本好看太多
4. 更新了 pdfboxxstreamcommon-io 等依赖的版本
> January 17th 2018
> 2021年1月28日
1. Refined the project directory, abstract file preview interface, Easy to extend more file extensions and depoly this project on your own
1. Added English documentation (@幻幻Fate@汝辉) contribution
1. Support for more image file extensions
1. Fixed the issue that image carousel in zip file will always start from the first
2020农历年最后一个版本发布主要包含了部分 UI 改进和解决了 QQ 群友 Issue 里反馈的 Bug 修复最最重要的是发个新版过个好年
> January 12th 2018
1. 引入galimatias,解决不规范文件名导致文件下载异常
2. 更新index接入演示界面UI风格
3. 更新markdown文件预览UI风格
4. 更新XML文件预览UI风格调整类文本预览架构更方便扩展
5. 更新simTxT文件预览UI风格
6. 调整多图连续预览上下翻图的UI
7. 采用apache-common-io包简化所有的文件下载io操作
8. XML文件预览支持切换纯文本模式
9. 增强url base64解码失败时的提示信息
10. 修复导包错误以及图片预览 bug
11. 修复发行包运行时找不到日志目录的问题
12. 修复压缩包内多图连续预览的bug
13. 修复大小写文件类型后缀没通用匹配的问题
14. 指定Base64转码采用Apache Commons-code中的实现修复base64部分jdk版本下出现的异常
15. 修复类文本类型HTML文件预览的bug
16. 修复dwg文件预览时无法在jpg和pdf两种类型之间切换
17. escaping of dangerous characters to prevent reflected xss
18. 修复重复编码导致文档转图片预览失败的问题&编码规范
1. Support for multiple images preview
1. Support for images rotation preview in rar/zip
> 2020年12月27日
> January 2nd 2018
2020年年终大版本更新架构全面设计代码全面重构代码质量全面提升二次开发更便捷欢迎拉源码品鉴提issuepr共同建设
1. Fixed gibberish issue when preview a txt document caused by the file encoding problem
1. Fixed the issue that some module dependencies can not be found
1. Add a spring boot profile, and support for Multi-environment configuration
1. Add `pdf.js` to preview the documents such as doc,etc.,support for generating doc headlines as pdf menusupport for mobile preview
1. 架构模块调整,大量的代码重构代码质量提升N个等级欢迎品鉴
2. 增强XML文件预览效果新增XML文档数结构预览
3. 新增markdown文件预览支持预览支持md渲染和源文本切换支持
4. 切换底层web server为jetty解决这个issuehttps://github.com/kekingcn/kkFileView/issues/168
5. 引入cpdetector解决文件编码识别问题
6. url采用base64+urlencode双编码彻底解决各种奇葩文件名预览问题
7. 新增配置项office.preview.switch.disabled控制offic文件预览切换开关
8. 优化文本类型文件预览逻辑采用Base64传输内容避免预览时再次请求文件内容
9. office预览图片模式禁用图片放大效果达到图片和pdf预览效果一致的体验
10. 直接代码静态设置pdfbox兼容低版本jdk在IDEA中运行也不会有警告提示
11. 移除guavahutool等非必须的工具包减少代码体积
12. Office组件加载异步化提速应用启动速度最快到5秒内
13. 合理设置预览消费队列的线程数
14. 修复压缩包里文件再次预览失败的bug
15. 修复图片预览的bug
> 2020年05月20日
1. 新增支持全局水印并支持通过参数动态改变水印内容
2. 新增支持CAD文件预览
3. 新增base.url配置支持使用nginx反向代理和使用context-path
4. 支持所有配置项支持从环境变量里读取方便Docker镜像部署和集群中大规模使用
5. 支持配置限信任站点只能预览来自信任点的文件源保护预览服务不被滥用
6. 支持配置自定义缓存清理时间cron表达式
7. 全部能识别的纯文本直接预览不用再转跳下载.md .java .py等
8. 支持配置限制转换后的PDF文件下载
9. 优化maven打包配置解决 .sh 脚本可能出现换行符问题
10. 将前端所有CDN依赖放到本地方便没有外网连接的用户使用
11. 首页评论服务由搜狐畅言切换到Gitalk
12. 修复url中包含特殊字符可能会引起的预览异常
13. 修复转换文件队列addTask异常
14. 修复其他已经问题
15. 官网建设[https://kkfileview.keking.cn](https://kkfileview.keking.cn)
16. 官方Docker镜像仓库建设[https://hub.docker.com/r/keking/kkfileview](https://hub.docker.com/r/keking/kkfileview)
> 2019年06月18日
1. 支持自动清理缓存及预览文件
2. 支持http/https下载流url文件预览
3. 支持FTP url文件预览
4. 加入Docker构建
> 2019年04月08日
1. 缓存及队列实现抽象提供JDK和REDIS两种实现(REDIS成为可选依赖)
2. 打包方式提供zip和tar.gz包并提供一键启动脚本
> 2018年01月19日
1. 大文件入队提前处理
1. 新增addTask文件转换入队接口
1. 采用redis队列支持kkFIleView接口和异构系统入队两种方式
> 2018年01月17日
1. 优化项目结构抽象文件预览接口更方便的加入更多的文件类型预览支持方便二次开发
1. 新增英文文档说明@幻幻Fate@汝辉贡献
1. 新增图片预览文件支持类型
1. 修复压缩包内轮播图片总是从第一张开始的问题
> 2018年01月12日
1. 新增多图片同时预览
1. 支持压缩包内图片轮番预览
> 2018年01月02日
1. 修复txt等文本编码问题导致预览乱码
1. 修复项目模块依赖引入不到的问题
1. 新增spring boot profile支持多环境配置
1. 引入pdf.js预览doc等文件支持doc标题生成pdf预览菜单支持手机端预览
### 使用登记
如果这个项目解决了你的实际问题可在 https://gitee.com/kekingcn/file-online-preview/issues/IGSBV
登记下如果节省了你的三方预览服务费用也愿意支持下的话可点击下方捐助请作者喝杯咖啡也是非常感谢
### Stars 趋势图
#### Gitee
[![Stargazers over time](https://whnb.wang/img/kekingcn/file-online-preview)](https://whnb.wang/kekingcn/file-online-preview?e=86400)
#### GitHub
[![Stargazers over time](https://starchart.cc/kekingcn/kkFileView.svg)](https://starchart.cc/kekingcn/kkFileView)
### Sponsor Us
If this project has been helpful to you, we welcome your sponsorship. Your support is our greatest motivation.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

BIN
doc/知识星球.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -14,12 +14,12 @@ RUN apt-get clean && apt-get update &&\
apt-get install -y fontconfig ttf-mscorefonts-installer ttf-wqy-microhei ttf-wqy-zenhei xfonts-wqy &&\
apt-get install -y wget &&\
cd /tmp &&\
wget https://kkfileview.keking.cn/server-jre-8u251-linux-x64.tar.gz &&\
wget https://kkview.cn/resource/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/ &&\
# 安装 libreoffice
apt-get install -y libxrender1 libxinerama1 libxt6 libxext-dev libfreetype6-dev libcairo2 libcups2 libx11-xcb1 libnss3 &&\
wget https://kkfileview.keking.cn/LibreOffice_7.3.7_Linux_x86-64_deb.tar.gz -cO libreoffice_deb.tar.gz &&\
wget https://kkview.cn/resource/LibreOffice_7.3.7_Linux_x86-64_deb.tar.gz -cO libreoffice_deb.tar.gz &&\
tar -zxf /tmp/libreoffice_deb.tar.gz && cd /tmp/LibreOffice_7.3.7.2_Linux_x86-64_deb/DEBS &&\
dpkg -i *.deb &&\

View File

@@ -1,129 +0,0 @@
<?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>
<artifactId>kkFileView-parent</artifactId>
<groupId>cn.keking</groupId>
<version>4.1.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.libreoffice</groupId>
<artifactId>libreoffice</artifactId>
<version>7.1.4</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>
<groupId>org.apache.maven.plugins</groupId>
<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>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/dist.xml</descriptor>
</descriptors>
</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.7</version>
</plugin>
</plugins>
</reporting>
</project>

View File

@@ -1,37 +0,0 @@
<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>

View File

@@ -1,123 +0,0 @@
//
// 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 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;
import org.artofsolving.jodconverter.office.OfficeContext;
import org.artofsolving.jodconverter.office.OfficeException;
import org.artofsolving.jodconverter.office.OfficeTask;
import java.io.File;
import java.util.Map;
import static org.artofsolving.jodconverter.office.OfficeUtils.*;
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);
@Override
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);
}
}
}

View File

@@ -1,83 +0,0 @@
//
// 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 com.sun.star.document.UpdateDocMode;
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.model.FileProperties;
import org.artofsolving.jodconverter.office.OfficeException;
import org.artofsolving.jodconverter.office.OfficeManager;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
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, null);
}
public void convert(File inputFile, File outputFile, FileProperties fileProperties) throws OfficeException {
String outputExtension = FilenameUtils.getExtension(outputFile.getName());
DocumentFormat outputFormat = formatRegistry.getFormatByExtension(outputExtension);
convert(inputFile, outputFile, outputFormat, fileProperties);
}
public void convert(File inputFile, File outputFile, DocumentFormat outputFormat, FileProperties fileProperties) throws OfficeException {
String inputExtension = FilenameUtils.getExtension(inputFile.getName());
DocumentFormat inputFormat = formatRegistry.getFormatByExtension(inputExtension);
Map<String, Object> properties = fileProperties.toMap();
properties.putAll(defaultLoadProperties);
StandardConversionTask conversionTask = new StandardConversionTask(inputFile, outputFile, outputFormat);
conversionTask.setDefaultLoadProperties(properties);
conversionTask.setInputFormat(inputFormat);
officeManager.execute(conversionTask);
}
}

View File

@@ -1,47 +0,0 @@
//
// 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());
}
}
}

View File

@@ -1,74 +0,0 @@
//
// 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);
}
}

View File

@@ -1,127 +0,0 @@
//
// 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 java.nio.charset.Charset;
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, Charset.defaultCharset()));
} 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();
}
}
}

View File

@@ -1,157 +0,0 @@
//
// 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);
}
}

View File

@@ -1,19 +0,0 @@
//
// 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
}

View File

@@ -1,99 +0,0 @@
//
// 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);
}
}

View File

@@ -1,25 +0,0 @@
//
// 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);
}

View File

@@ -1,74 +0,0 @@
//
// 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.nio.charset.Charset;
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, Charset.defaultCharset()));
}
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;
}
}

View File

@@ -1,65 +0,0 @@
//
// 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;
}
}

View File

@@ -1,34 +0,0 @@
package org.artofsolving.jodconverter.model;
import java.util.HashMap;
import java.util.Map;
/**
* Created by kl on 2018/1/17.
* Content :
*/
public class FileProperties {
private String filePassword;
public FileProperties() {
}
public Map<String, Object> toMap() {
Map<String, Object> map = new HashMap<>();
if (filePassword != null) {
map.put("Password", filePassword);
}
return map;
}
public String getFilePassword() {
return filePassword;
}
public void setFilePassword(String filePassword) {
this.filePassword = filePassword;
}
}

View File

@@ -1,223 +0,0 @@
//
// 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();
}
}

View File

@@ -1,86 +0,0 @@
//
// 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();
}
}

View File

@@ -1,47 +0,0 @@
//
// 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);
}
}

View File

@@ -1,176 +0,0 @@
//
// 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();
}
}

View File

@@ -1,97 +0,0 @@
//
// 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;
}
}

View File

@@ -1,43 +0,0 @@
//
// 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;
}
}

View File

@@ -1,117 +0,0 @@
//
// 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);
}
}
}

View File

@@ -1,25 +0,0 @@
//
// 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);
}
}

View File

@@ -1,23 +0,0 @@
//
// 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);
}

View File

@@ -1,15 +0,0 @@
//
// 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 }

View File

@@ -1,19 +0,0 @@
//
// 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);
}

View File

@@ -1,26 +0,0 @@
//
// 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);
}
}

View File

@@ -1,30 +0,0 @@
//
// 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();
}

View File

@@ -1,210 +0,0 @@
//
// 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.nio.charset.Charset;
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, Charset.defaultCharset()).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, Charset.defaultCharset()).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);
}
}

View File

@@ -1,19 +0,0 @@
//
// 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;
}

View File

@@ -1,172 +0,0 @@
//
// 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";
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/libreoffice7.3",
"/opt/libreoffice7.4",
"/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);
}
}
}
}

View File

@@ -1,110 +0,0 @@
//
//
// 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();
}
}

View File

@@ -1,43 +0,0 @@
//
// 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;
}
}

View File

@@ -1,110 +0,0 @@
//
// 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;
}
}

View File

@@ -1,23 +0,0 @@
//
// 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);
}
}

View File

@@ -1,55 +0,0 @@
//
// 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
}
}
}

View File

@@ -1,59 +0,0 @@
//
// 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();
}
}
}

View File

@@ -1,32 +0,0 @@
//
// 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"));
}
}

View File

@@ -1,62 +0,0 @@
//
// 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;
}
}

View File

@@ -1,80 +0,0 @@
//
// 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.nio.charset.Charset;
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
*/
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();
return IOUtils.readLines(process.getInputStream(), Charset.defaultCharset());
}
}

View File

@@ -1,32 +0,0 @@
//
// 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;
}

View File

@@ -1,33 +0,0 @@
//
// 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;
}
}

View File

@@ -1,25 +0,0 @@
//
// 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();
}
}

View File

@@ -1,71 +0,0 @@
//
// 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;
}
}

View File

@@ -1,35 +0,0 @@
//
// 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");
}
}

View File

@@ -1,188 +0,0 @@
[
{
"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"}}
}
]

View File

@@ -6,11 +6,12 @@
<groupId>cn.keking</groupId>
<artifactId>kkFileView-parent</artifactId>
<version>4.1.0</version>
<version>4.2.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<jodconverter.version>4.4.5</jodconverter.version>
<spring.boot.version>2.4.2</spring.boot.version>
<poi.version>5.2.2</poi.version>
<xdocreport.version>1.0.6</xdocreport.version>
@@ -18,7 +19,6 @@
<junrar.version>7.4.1</junrar.version>
<redisson.version>3.2.0</redisson.version>
<sevenzipjbinding.version>16.02-2.01</sevenzipjbinding.version>
<tukaani.version>1.8</tukaani.version>
<jchardet.version>1.0</jchardet.version>
<antlr.version>2.7.7</antlr.version>
<concurrentlinkedhashmap.version>1.4.2</concurrentlinkedhashmap.version>
@@ -37,7 +37,7 @@
<commons-cli.version>1.2</commons-cli.version>
<commons-net.version>3.6</commons-net.version>
<commons-lang3.version>3.7</commons-lang3.version>
<commons-compress.version>1.21</commons-compress.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
@@ -47,7 +47,6 @@
</properties>
<modules>
<module>office-plugin</module>
<module>server</module>
</modules>

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 937 B

After

Width:  |  Height:  |  Size: 937 B

View File

Before

Width:  |  Height:  |  Size: 858 B

After

Width:  |  Height:  |  Size: 858 B

View File

Before

Width:  |  Height:  |  Size: 894 B

After

Width:  |  Height:  |  Size: 894 B

View File

Before

Width:  |  Height:  |  Size: 787 B

After

Width:  |  Height:  |  Size: 787 B

View File

Before

Width:  |  Height:  |  Size: 386 B

After

Width:  |  Height:  |  Size: 386 B

View File

Before

Width:  |  Height:  |  Size: 727 B

After

Width:  |  Height:  |  Size: 727 B

View File

Before

Width:  |  Height:  |  Size: 733 B

After

Width:  |  Height:  |  Size: 733 B

View File

Before

Width:  |  Height:  |  Size: 776 B

After

Width:  |  Height:  |  Size: 776 B

View File

Before

Width:  |  Height:  |  Size: 956 B

After

Width:  |  Height:  |  Size: 956 B

View File

Before

Width:  |  Height:  |  Size: 748 B

After

Width:  |  Height:  |  Size: 748 B

View File

Before

Width:  |  Height:  |  Size: 742 B

After

Width:  |  Height:  |  Size: 742 B

View File

Before

Width:  |  Height:  |  Size: 941 B

After

Width:  |  Height:  |  Size: 941 B

View File

Before

Width:  |  Height:  |  Size: 983 B

After

Width:  |  Height:  |  Size: 983 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 466 B

After

Width:  |  Height:  |  Size: 466 B

View File

Before

Width:  |  Height:  |  Size: 572 B

After

Width:  |  Height:  |  Size: 572 B

View File

Before

Width:  |  Height:  |  Size: 464 B

After

Width:  |  Height:  |  Size: 464 B

View File

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 508 B

View File

Before

Width:  |  Height:  |  Size: 621 B

After

Width:  |  Height:  |  Size: 621 B

View File

Before

Width:  |  Height:  |  Size: 656 B

After

Width:  |  Height:  |  Size: 656 B

View File

Before

Width:  |  Height:  |  Size: 315 B

After

Width:  |  Height:  |  Size: 315 B

View File

Before

Width:  |  Height:  |  Size: 98 B

After

Width:  |  Height:  |  Size: 98 B

Some files were not shown because too many files have changed in this diff Show More