• Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе

    «Анализ защищенности веб-приложений»

    🔥 Записаться бесплатно!

  • CTF с учебными материалами Codeby Games

    Обучение кибербезопасности в игровой форме. Более 200 заданий по Active Directory, OSINT, PWN, Веб, Стеганографии, Реверс-инжинирингу, Форензике и Криптографии. Школа CTF с бесплатными курсами по всем категориям.

xdocreport

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 933
609
BIT
177
решил вынести в отдельную тему...
во-первых - помним про сесуриту
второй момент - если хочется тестить "в БД", т.е. загрузить файлы ворда в базу, надо учесть ряд особенностей:

что ресурсы должны "лежать" в res агента! (даже при вызове классов Java либы в написанной в нотусе)
upload_2017-4-21_19-19-21.png

и лучше использовать конструкцию:
Java:
getClass().getClassLoader().getResourceAsStream("имяфайла");
т.е. без "ненужного" слеша
либы, кот так или иначе могут использоваться (в т.ч. для генерации ПДФ):
commons-codec-1.10.jar
commons-collections-3.2.1.jar
commons-collections4-4.1.jar
commons-lang-2.4.jar
fr.opensagres.odfdom.converter.core-2.0.0.jar
fr.opensagres.odfdom.converter.pdf-2.0.0.jar
fr.opensagres.odfdom.converter.xhtml-2.0.0.jar
fr.opensagres.poi.xwpf.converter.core-2.0.0.jar
fr.opensagres.poi.xwpf.converter.pdf-2.0.0.jar
fr.opensagres.poi.xwpf.converter.xhtml-2.0.0.jar
fr.opensagres.xdocreport.converter-2.0.0-javadoc.jar
fr.opensagres.xdocreport.converter-2.0.0.jar
fr.opensagres.xdocreport.converter.docx.xwpf-2.0.0-javadoc.jar
fr.opensagres.xdocreport.converter.docx.xwpf-2.0.0.jar
fr.opensagres.xdocreport.converter.odt.odfdom-2.0.0-javadoc.jar
fr.opensagres.xdocreport.converter.odt.odfdom-2.0.0.jar
fr.opensagres.xdocreport.core-2.0.0.jar
fr.opensagres.xdocreport.itext.extension-2.0.0.jar
fr.opensagres.xdocreport.template-2.0.0.jar
fr.opensagres.xdocreport.template.freemarker-2.0.0-javadoc.jar
fr.opensagres.xdocreport.template.freemarker-2.0.0.jar
freemarker-2.3.20.jar
itext-2.1.7.jar
odfdom-java-0.8.7.jar
ooxml-schemas-1.3.jar
oro-2.0.8.jar
poi-3.15.jar
poi-ooxml-3.15-javadoc.jar
poi-ooxml-3.15.jar
poi-ooxml-schemas-3.15.jar
stax-api-1.0.1.jar
velocity-1.7.jar
xdocreport-2.0.0-javadoc.jar
xdocreport-2.0.0.jar
xercesImpl-2.9.1.jar
xml-apis-1.3.04.jar
POI 3.0.15 (я его пользую для парсинга эхеля), кот. я решил использовать имеет ряд особенностей
и если код. был написан для предыдущих версий - возможно придется корректировать
[doublepost=1493125006,1492792059][/doublepost]нек. особенности..
в проект можно добавить файл, через package explorer , но надо Refresh и сохранение агента
иначе он не перенесет файл в пути классов, тоже касается и изменения файла - надо вынудить агент на сохранение (изменить класс или ч-л еще)
иначе будет старая версия файла доступна классам!
[doublepost=1493224896][/doublepost]еще момент...
положить все в jvm/lib/ext - это вариант, но поддерживать либы в актуально состоянии тяжко
что можем сделать?!
я использую для создания базового ф-ционала Idea IntellyJ, т.е. все без нотусевой части обкатываю там, затем создаю артефакт, в кот. подкачиваются все либы (есть такая опция)
upload_2017-4-26_19-25-13.png
upload_2017-4-26_19-28-8.png

с зависимостями, но надо указать link via manifest
upload_2017-4-26_19-29-40.png


далее собираем артифакт и... хачим получившийся jar (можем скопировать, чтобы пользоваться оригиналом)
я его копию называю loopback.jar (название не суть)
удаляю всю иерархию классов из него (открывая как архив)
и меняю манифест, для случая с xdocreport получим так:
Manifest-Version: 1.0
Class-Path: fr.opensagres.xdocreport.converter.odt.odfdom-2.0.0.jar fr
.opensagres.xdocreport.converter-2.0.0.jar fr.opensagres.xdocreport.c
ore-2.0.0.jar fr.opensagres.odfdom.converter.pdf-2.0.0.jar fr.opensag
res.odfdom.converter.core-2.0.0.jar odfdom-java-0.8.7.jar xercesImpl-
2.9.1.jar xml-apis-1.3.04.jar fr.opensagres.xdocreport.itext.extensio
n-2.0.0.jar itext-2.1.7.jar fr.opensagres.odfdom.converter.xhtml-2.0.
0.jar org.osgi.core-4.2.0.jar fr.opensagres.xdocreport.template.freem
arker-2.0.0.jar fr.opensagres.xdocreport.template-2.0.0.jar fr.opensa
gres.xdocreport.core-2.0.0.jar freemarker-2.3.20.jar fr.opensagres.xd
ocreport.template.freemarker-2.0.0.jar fr.opensagres.xdocreport.templ
ate-2.0.0.jar fr.opensagres.xdocreport.core-2.0.0.jar freemarker-2.3.
20.jar org.osgi.core-4.2.0.jar oro-2.0.8.jar velocity-1.7.jar commons
-lang-2.4.jar xdocreport-2.0.0.jar org.osgi.core-4.2.0.jar poi-ooxml-
3.15.jar poi-3.15.jar commons-codec-1.10.jar commons-collections4-4.1
.jar poi-ooxml-schemas-3.15.jar xmlbeans-2.6.0.jar stax-api-1.0.1.jar
commons-collections-3.2.1.jar fr.opensagres.xdocreport.converter.doc
x.xwpf-2.0.0.jar fr.opensagres.xdocreport.converter-2.0.0.jar fr.open
sagres.xdocreport.core-2.0.0.jar fr.opensagres.poi.xwpf.converter.pdf
-2.0.0.jar fr.opensagres.poi.xwpf.converter.core-2.0.0.jar commons-co
dec-1.10.jar ooxml-schemas-1.3.jar stax-api-1.0.1.jar fr.opensagres.x
docreport.itext.extension-2.0.0.jar itext-2.1.7.jar fr.opensagres.poi
.xwpf.converter.xhtml-2.0.0.jar org.osgi.core-4.2.0.jar
Main-Class: Loopback
т.е. на всяк случай переназвал Main-Class (для нашей цели - не имеет значения)
далее - кладем все файлы из каталога артефакта в "нужный" на сервере (я говорю в контексте сервера, но для клиента - нет отличий)
"нужный" - это любой, доступный пользователю, под кот. запущена домина/нотус
и финальный момент - правим notes.ini
у меня он получился такой (значимый кусок):
...
JavaUserClassesExt=XDP-_0
XDP-_0=/home/local/notesdata/xdocreport+POI/loopback.jar
...
перезапускаем сервер/клиент - либы у нас в доступе и собраны в одном месте
про этот подход я уже рассказывал
можно jar создавать кодом - "но руки не дошли"
 
K

Kee_Keekkenen

о наболевшем (не у меня).. коллега, сейчас пилит формирование печатных форм, на устаревшей версии itext (не известно даже на какой), а я параллельно на itext5 аналогично создаю печатные формы по пути данные --> xml --> xsl --> itext5(html + css) = pdf

артифактами еще не пользовался, а зачем так извращаться ?
можно просто сделать maven проект, в настройках оного в dependencies прописать все зависимости - библиотеки что в итоге должны попасть в Class-Path манифеста, для примера, пара первых библиотек
Код:
<dependencies>
  <dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>fr.opensagres.xdocreport.converter.odt.odfdom</artifactId>
    <version>2.0.0</version>
  </dependency>
  
  <dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>fr.opensagres.xdocreport.converter</artifactId>
    <version>2.0.0</version>
  </dependency>
</dependencies>
соответственно, чтобы это добро добавилось в манифест, нужно для maven-jar-plugin пару параметров
Код:
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <version>3.0.2</version>
  <configuration>
    <archive>
      <manifest>
        <addClasspath>true</addClasspath>
        <!--класс должен быть в пакете-->
        <mainClass>test.Loopback</mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 933
609
BIT
177
можно просто сделать maven проект, в настройках оного в dependencies прописать все зависимости - библиотеки что в итоге должны попасть в Class-Path манифеста, для примера, пара первых библиотек
что получим на выходе?
цель была получить 1-ин! jar, на кот. можно сослаться из notes.ini
и зачем мне что-то прописывать в файлах мавена, если ИДЕ делает это сама? ;)
суть проста: я разрабатываю приложение, кот. потом переношу в нотусню, мне нужно - чтобы все либы для приложения попали в пути jvm нотусни (ограничение на 255 символов, для строки, в notes.ini)
при этом - приложение как самостоятельная сущность останется полностью ф-циональным, при запуске через jar
[doublepost=1493283178,1493283015][/doublepost]и да... - репы мавена идеи порой тянут "лишние" либы и этот "мусор" не нужен в нотусне, а "тут" я могу почистить, визуально
а создавать локальные репы по каждому чиху - ну очнехоца
[doublepost=1493283621][/doublepost]про itext - он в зависимостях xdocreport, для XWPF->iText->PDF
у него есть дижок на FOP, но он считается тестовым
если задействовать FOP - я уже описывал варианты здесь же, для POI (у него готовый конвертор DOCX->FOP)
 
K

Kee_Keekkenen

не вижу тут проблемы - вот пример по твоим библиотекам (не уверен, что правильно опознал itext-2.1.7),
кстати этот itext (тот, что я прописал в настройках проекта) в класспас манифеста выводил зависимости от
bouncycastle, я их и выключил - получился "чистый" класспас..

в твоем Class-Path манифеста есть xdocreport-2.0.0.jar, я так и не понял что это такое, может это самописаная либа.. но не суть.. из-за ее отсутствия я не смог ее прописать в пом и, соответственно, она не попала в класспас.. если это самописная либа, то ее можно добавить в локальный репозитарий и прописать в пом и тогда она как и все прочие попадут в манифест.. прилагаю, jar в нем можно взять пом файл, если есть желание автоматом формировать такие "лупы"
 

Вложения

  • loopback-1.0.zip
    2,3 КБ · Просмотры: 230

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 933
609
BIT
177
@Kee_Keekkenen проблемы нет ;) есть нежелание что-то прописывать руками, в текстовом файле...
добавлять локальные репы и т.п. - это неудобно, если нет необхордимости
это из реп и там core классы
[doublepost=1493376198,1493374771][/doublepost]расскажу про особенности с формированием ПДФ.
1- надо включать используемые шрифты в документ! НО - чтобы не раздувать файл - включать только используемые символы (опция ворда). У меня файл 400К вырос до 3М , при включении полного набора, что накладно
2 - картинки, кот. д.б. включены лучше сразу отресайзить, под конечный размер, и проверить на их "совместимость" с движком. Если движок плюнет предупреждение (в консоль) - картинку надо выгрузить как PNG и загрузить обратно вместо существующей (да - в вордятину могут вставлять всякую херь)
3 - картинки вполне-себе поддерживают прозрачность, вот только виндоюзеры об этом не знают ;). Резьюм - использовать альфа-канал (я делал в Gimp) вместо белого фона.

все указанные действия в разы сокращают объем файла результата, и как следствие - уменьшают потребление памяти!

4 - никаких отступов для "сшивания" в параметрах страницы вордятины! Этот параметр не отрабатывается корректно (и является бессмысленным, с моей т.з.). Все вполне решается настройкой отступов в документе
5 - сука-ворд не учитывает особенности границ таблицы и ячеек, он тупо считает - либо все либо ничего, очень долго боролся с сочетанием этих параметров, чтобы получить адекватное отображение. Поэтому - у внутренних ячеек пришлось делать границы в 2-а раза тоньше (т.к. они будут складываться), чем у "внешних". Т.е. - отображение вордом, и при печати будет плевать на этот момент, а в ПДФ сразу "вылезет"

почему была борьба за память - используется формирование объектов в памяти, для ПДФ, и как результат - время обработки и память будут существенно завязаны на размер исходного файла
само формирование можно сделать так:
Java:
...
                out = new FileOutputStream(new File(
                        "DocxTableWithoutFieldsMetadataWithVelocity_Out.pdf"));
                Options options = Options.getTo(ConverterTypeTo.PDF).via(
                        ConverterTypeVia.XWPF);
                report.convert(context, options, out);
...
при соблюдении пунктов, результат все-равно будет отличаться от вордятины, но не ужасен (если рекомендации не соблюдать)
[doublepost=1493378084][/doublepost]размещу свои изыскания по теме - как обойтись без выгрузки/загрузки в Файловую Систему (ФС)
это желание (не сохранять, явно, в ФС) связано со многими похотелками, в т.ч. сесуриту (security) в агентах и нежеланием заморачиваться на временные файлы (хотя и этот код у меня имеется)
просто очень решается с InputStream - штатно:
Java:
          Session session = getSession();
          AgentContext agentContext = session.getAgentContext();
          Document doc = agentContext.getDocumentContext();
          if (doc!=null) {
              System.out.println("processsing document:" + doc.getUniversalID());
              Vector<EmbeddedObject> objs;//=doc.getEmbeddedObjects();
              RichTextItem body =
                  (RichTextItem)
                  doc.getFirstItem("Body");
              objs=body.getEmbeddedObjects();
              List<EmbeddedObject> list=new ArrayList<EmbeddedObject>();
              list.addAll(objs);
              BatchesInfo batchesInfo=new BatchesInfo();
              batchesInfo.setUnid(doc.getUniversalID());
              for(EmbeddedObject obj:list) {
                  System.out.println("object Name:"+obj.getName());
                  batchesInfo.processIn1(obj.getInputStream());
              }
использование list - нежелание работать с Vector (старый подход, кот. индусы так и не удосужились переписать)
но самое интересное нас ждет в получении OutputStream - нет такой возможности в нотусятине (очередные лучи поноса в сторону индусов)
как "так получилось" - я не могу предположить, но сделать Stream несовместимым с OutputStream - это особо тонкое издевательство со стороны ИИБМ (Индусы ИБМ)
беглый поиск по засовыванию в РТ приводил к обрывкам кода, но целостного решения я так и не видел (а лень очень велика - писать самому), к счастью нашел это
разумеется - это не решало проблемы засовывания бинарного файла в РТ (и не пробуйте ;))
я пошел путем... mime
для этого пригодился обрывок
стандарты
и плевок (что и не удивительно) от МС:
ссылку нашел через... гугл +
ОФФ: вот с МС продуктами всегда так - первые ссылки никогда не приводят к ответу на их сайте ;)
используя Kate (мну нра этот простой редактор, в КДЕ) и регэкспы, я наманячил Map:
Java:
import java.util.HashMap;
import java.util.Map;
//http://w3schools.sinsixx.com/media/media_mimeref.asp.htm
public class MIMEType {
private static final Map<String, String> map=createMap();
private static final String defType = "application/octet-stream";

public static String get(String key) {
    if (map.containsKey(key))return map.get(key);
    return defType;
}

private static Map<String, String> createMap() {
    // TODO Auto-generated method stub
    Map<String,String> map=new HashMap<String,String>();
    map.put("323","text/h323");
    map.put("acx","application/internet-property-stream");
    map.put("ai","application/postscript");
    map.put("aif","audio/x-aiff");
    map.put("aifc","audio/x-aiff");
    map.put("aiff","audio/x-aiff");
    map.put("asf","video/x-ms-asf");
    map.put("asr","video/x-ms-asf");
    map.put("asx","video/x-ms-asf");
    map.put("au","audio/basic");
    map.put("avi","video/x-msvideo");
    map.put("axs","application/olescript");
    map.put("bas","text/plain");
    map.put("bcpio","application/x-bcpio");
    map.put("bin","application/octet-stream");
    map.put("bmp","image/bmp");
    map.put("c","text/plain");
    map.put("cat","application/vnd.ms-pkiseccat");
    map.put("cdf","application/x-cdf");
    map.put("cer","application/x-x509-ca-cert");
    map.put("class","application/octet-stream");
    map.put("clp","application/x-msclip");
    map.put("cmx","image/x-cmx");
    map.put("cod","image/cis-cod");
    map.put("cpio","application/x-cpio");
    map.put("crd","application/x-mscardfile");
    map.put("crl","application/pkix-crl");
    map.put("crt","application/x-x509-ca-cert");
    map.put("csh","application/x-csh");
    map.put("css","text/css");
    map.put("dcr","application/x-director");
    map.put("der","application/x-x509-ca-cert");
    map.put("dir","application/x-director");
    map.put("dll","application/x-msdownload");
    map.put("dms","application/octet-stream");
    map.put("doc","application/msword");
    map.put("dot","application/msword");
    map.put("dvi","application/x-dvi");
    map.put("dxr","application/x-director");
    map.put("eps","application/postscript");
    map.put("etx","text/x-setext");
    map.put("evy","application/envoy");
    map.put("exe","application/octet-stream");
    map.put("fif","application/fractals");
    map.put("flr","x-world/x-vrml");
    map.put("gif","image/gif");
    map.put("gtar","application/x-gtar");
    map.put("gz","application/x-gzip");
    map.put("h","text/plain");
    map.put("hdf","application/x-hdf");
    map.put("hlp","application/winhlp");
    map.put("hqx","application/mac-binhex40");
    map.put("hta","application/hta");
    map.put("htc","text/x-component");
    map.put("htm","text/html");
    map.put("html","text/html");
    map.put("htt","text/webviewhtml");
    map.put("ico","image/x-icon");
    map.put("ief","image/ief");
    map.put("iii","application/x-iphone");
    map.put("ins","application/x-internet-signup");
    map.put("isp","application/x-internet-signup");
    map.put("jfif","image/pipeg");
    map.put("jpe","image/jpeg");
    map.put("jpeg","image/jpeg");
    map.put("jpg","image/jpeg");
    map.put("js","application/x-javascript");
    map.put("latex","application/x-latex");
    map.put("lha","application/octet-stream");
    map.put("lsf","video/x-la-asf");
    map.put("lsx","video/x-la-asf");
    map.put("lzh","application/octet-stream");
    map.put("m13","application/x-msmediaview");
    map.put("m14","application/x-msmediaview");
    map.put("m3u","audio/x-mpegurl");
    map.put("man","application/x-troff-man");
    map.put("mdb","application/x-msaccess");
    map.put("me","application/x-troff-me");
    map.put("mht","message/rfc822");
    map.put("mhtml","message/rfc822");
    map.put("mid","audio/mid");
    map.put("mny","application/x-msmoney");
    map.put("mov","video/quicktime");
    map.put("movie","video/x-sgi-movie");
    map.put("mp2","video/mpeg");
    map.put("mp3","audio/mpeg");
    map.put("mpa","video/mpeg");
    map.put("mpe","video/mpeg");
    map.put("mpeg","video/mpeg");
    map.put("mpg","video/mpeg");
    map.put("mpp","application/vnd.ms-project");
    map.put("mpv2","video/mpeg");
    map.put("ms","application/x-troff-ms");
    map.put("mvb","application/x-msmediaview");
    map.put("nws","message/rfc822");
    map.put("oda","application/oda");
    map.put("p10","application/pkcs10");
    map.put("p12","application/x-pkcs12");
    map.put("p7b","application/x-pkcs7-certificates");
    map.put("p7c","application/x-pkcs7-mime");
    map.put("p7m","application/x-pkcs7-mime");
    map.put("p7r","application/x-pkcs7-certreqresp");
    map.put("p7s","application/x-pkcs7-signature");
    map.put("pbm","image/x-portable-bitmap");
    map.put("pdf","application/pdf");
    map.put("pfx","application/x-pkcs12");
    map.put("pgm","image/x-portable-graymap");
    map.put("pko","application/ynd.ms-pkipko");
    map.put("pma","application/x-perfmon");
    map.put("pmc","application/x-perfmon");
    map.put("pml","application/x-perfmon");
    map.put("pmr","application/x-perfmon");
    map.put("pmw","application/x-perfmon");
    map.put("pnm","image/x-portable-anymap");
    map.put("pot,","application/vnd.ms-powerpoint");
    map.put("ppm","image/x-portable-pixmap");
    map.put("pps","application/vnd.ms-powerpoint");
    map.put("ppt","application/vnd.ms-powerpoint");
    map.put("prf","application/pics-rules");
    map.put("ps","application/postscript");
    map.put("pub","application/x-mspublisher");
    map.put("qt","video/quicktime");
    map.put("ra","audio/x-pn-realaudio");
    map.put("ram","audio/x-pn-realaudio");
    map.put("ras","image/x-cmu-raster");
    map.put("rgb","image/x-rgb");
    map.put("rmi","audio/mid");
    map.put("roff","application/x-troff");
    map.put("rtf","application/rtf");
    map.put("rtx","text/richtext");
    map.put("scd","application/x-msschedule");
    map.put("sct","text/scriptlet");
    map.put("setpay","application/set-payment-initiation");
    map.put("setreg","application/set-registration-initiation");
    map.put("sh","application/x-sh");
    map.put("shar","application/x-shar");
    map.put("sit","application/x-stuffit");
    map.put("snd","audio/basic");
    map.put("spc","application/x-pkcs7-certificates");
    map.put("spl","application/futuresplash");
    map.put("src","application/x-wais-source");
    map.put("sst","application/vnd.ms-pkicertstore");
    map.put("stl","application/vnd.ms-pkistl");
    map.put("stm","text/html");
    map.put("svg","image/svg+xml");
    map.put("sv4cpio","application/x-sv4cpio");
    map.put("sv4crc","application/x-sv4crc");
    map.put("swf","application/x-shockwave-flash");
    map.put("t","application/x-troff");
    map.put("tar","application/x-tar");
    map.put("tcl","application/x-tcl");
    map.put("tex","application/x-tex");
    map.put("texi","application/x-texinfo");
    map.put("texinfo","application/x-texinfo");
    map.put("tgz","application/x-compressed");
    map.put("tif","image/tiff");
    map.put("tiff","image/tiff");
    map.put("tr","application/x-troff");
    map.put("trm","application/x-msterminal");
    map.put("tsv","text/tab-separated-values");
    map.put("txt","text/plain");
    map.put("uls","text/iuls");
    map.put("ustar","application/x-ustar");
    map.put("vcf","text/x-vcard");
    map.put("vrml","x-world/x-vrml");
    map.put("wav","audio/x-wav");
    map.put("wcm","application/vnd.ms-works");
    map.put("wdb","application/vnd.ms-works");
    map.put("wks","application/vnd.ms-works");
    map.put("wmf","application/x-msmetafile");
    map.put("wps","application/vnd.ms-works");
    map.put("wri","application/x-mswrite");
    map.put("wrl","x-world/x-vrml");
    map.put("wrz","x-world/x-vrml");
    map.put("xaf","x-world/x-vrml");
    map.put("xbm","image/x-xbitmap");
    map.put("xla","application/vnd.ms-excel");
    map.put("xlc","application/vnd.ms-excel");
    map.put("xlm","application/vnd.ms-excel");
    map.put("xls","application/vnd.ms-excel");
    map.put("xlt","application/vnd.ms-excel");
    map.put("xlw","application/vnd.ms-excel");
    map.put("xof","x-world/x-vrml");
    map.put("xpm","image/x-xpixmap");
    map.put("xwd","image/x-xwindowdump");
    map.put("z","application/x-compress");
    map.put("zip","application/zip");
    map.put(".xlsx","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    map.put(".xltx","application/vnd.openxmlformats-officedocument.spreadsheetml.template");
    map.put(".xlsm","application/vnd.ms-excel.sheet.macroEnabled.12");
    map.put(".xltm","application/vnd.ms-excel.template.macroEnabled.12");
    map.put(".xlam","application/vnd.ms-excel.addin.macroEnabled.12");
    map.put(".xlsb","application/vnd.ms-excel.sheet.binary.macroEnabled.12");
    map.put(".pptx","application/vnd.openxmlformats-officedocument.presentationml.presentation");
    map.put(".potx","application/vnd.openxmlformats-officedocument.presentationml.template");
    map.put(".ppsx","application/vnd.openxmlformats-officedocument.presentationml.slideshow");
    map.put(".ppam","application/vnd.ms-powerpoint.addin.macroEnabled.12");
    map.put(".pptm","application/vnd.ms-powerpoint.presentation.macroEnabled.12");
    map.put(".potm","application/vnd.ms-powerpoint.template.macroEnabled.12");
    map.put(".ppsm","application/vnd.ms-powerpoint.slideshow.macroEnabled.12");

    return map;
}
}
не.., ну можно было в пропертя сунуть, но... - писать доп. код и заморачиваться с расположением файл (опять же) было влом, учтем что и с UTF-8 в property файлах не все так однозначно ;)
короче - сделал для экономии своих нервов и времени
ну самой интересный момент... "коверкание" класса под mime:
Java:
//source from http://www.nsftools.com/tips/RichTextOutputStream.java
import java.io.IOException;
import java.io.OutputStream;
import lotus.domino.*;

import java.util.*;
import java.io.*;

public class RichTextOutputStream extends OutputStream {
    //private static final int MAX_BUF = 524288;//2048;
    private static final int MAX_BUF = 2048;
    private RichTextItem rtitem;
    private boolean convertLF = true;
    private boolean saveOnClose = false;
    private Session ses =null;
    private Stream stream =null;
    //private Database db=null;
    private MIMEEntity body =null;
    private String fileName="defname";
    private byte[] buffer=new byte[MAX_BUF];
    private int count;
 
    void setFileName(String fileName) {
        this.fileName = fileName;
    }

    String getFileName() {
        return fileName;
    }

    /**
     * Create a RichTextOutputStream using the specified Notes RichTextItem
     * as a target.
     *
     * @param  item     the RichTextItem that we're writing to
     * @throws NotesException
     */
    public RichTextOutputStream (RichTextItem item) throws NotesException {
        this(item, true, false);
    }
 
    /**
     * Create a RichTextOutputStream using the specified Notes RichTextItem
     * as a target, specifying whether or not linefeeds should automatically be
     * converted to new RichText lines as they are encountered.
     *
     * @param  item     the RichTextItem that we're writing to
     * @param  convertLinefeeds     a boolean value indicating whether linefeeds
     *                                          should be converted to new RichText lines
     *                                          (true, the default behavior) or sent to the
     *                                          RichTextItem as raw characters (false)
     * @throws NotesException
     */
    public RichTextOutputStream (RichTextItem item, boolean convertLinefeeds) throws NotesException {
        this(item, convertLinefeeds, false);
    }
 
    /**
     * Create a RichTextOutputStream using the specified Notes RichTextItem
     * as a target, specifying whether or not linefeeds should automatically be
     * converted to new RichText lines as they are encountered, and whether
     * or not the document that the RichTextItem is in should be automatically
     * saved when the stream is closed using the close() method.
     *
     * @param  item     the RichTextItem that we're writing to
     * @param  convertLinefeeds     a boolean value indicating whether linefeeds
     *                                          should be converted to new RichText lines
     *                                          (true, the default behavior) or sent to the
     *                                          RichTextItem as raw characters (false)
     * @param  shouldSave               a boolean value indicating whether the RichTextItem's
     *                                          parent Document should be saved when the close()
     *                                          method is called (true) or not (false, the default behavior)
     * @throws NotesException
     */
    public RichTextOutputStream (RichTextItem item, boolean convertLinefeeds, boolean shouldSave) throws NotesException {
        rtitem = item;
        setConvert(convertLinefeeds);
        setSaveOption(shouldSave);
    }
 
    public RichTextOutputStream(String name, Document doc) throws NotesException {
        ses=NotesFactory.createSession();
        stream=ses.createStream();
        ses.setConvertMIME(false);
        //db=doc.getParentDatabase();
        body=doc.createMIMEEntity(name);
        //rtitem=doc.createRichTextItem(name);
    }
 
    /**
     * Changes the behaivor of the stream, so that it either automatically converts
     * \r and \n linefeeds to new RichText lines when they are encountered (the
     * default behavior) or not. Note that this behavior can be changed at any time
     * as the stream is being written to, although it affects only new data that is written
     * to the RichTextItem, not data that has already been written.
     *
     * @param  convertLinefeeds     a boolean value indicating whether linefeeds
     *                                          should be converted to new RichText lines
     *                                          (true, the default behavior) or sent to the
     *                                          RichTextItem as raw characters (false)
     */
    public void setConvert (boolean convertLinefeeds) {
        convertLF = convertLinefeeds;
    }
 
    /**
     * Changes the behavior of the stream when the close() method is called,
     * so that it either causes the Document that contains the RichTextItem to be
     * saved or it doesn't (default is that it doesn't).
     *
     * @param  shouldSave               a boolean value indicating whether the RichTextItem's
     *                                          parent Document should be saved when the close()
     *                                          method is called (true) or not (false, the default behavior)
     */
    public void setSaveOption (boolean shouldSave) {
        saveOnClose = shouldSave;
    }
 
    /**
     * Returns the RichTextItem that the stream is currently writing to; convenient if
     * you've passed the RichTextOutputStream to a method and you need to access
     * the underlying RichTextItem directly.
     *
     * @return    the Notes RichTextItem that this stream writes to
     */
    public RichTextItem getRichTextItem () {
        return rtitem;
    }
 
    /**
     * Closes the RichTextOutputStream, so that no more data can be written to it.
     */
    public void close () throws IOException {
        flush();
        //System.out.println("Closing...");
        if (saveOnClose)
            save();
        rtitem = null;
        super.close();
    }
 
    /**
     * Overrides the default flush() method in the OutputStream class, although this
     * method really does nothing, because we're not buffering data and we're always
     * writing directly to the underlying RichTextItem.
     */
    public void flush () {
        // since we're always writing directly to the RichTextField,
        // this doesn't really do anything
        //System.out.println("Flusing...");
        try {
            if (stream!=null && stream.getBytes()>0) {
                    if (count>0) {flush2Stream(buffer);}
                    if (stream.getBytes()>0){
                        final MIMEEntity child = body.createChildEntity();
                        MIMEHeader header = child.createHeader("Content-Disposition");
                        header.setHeaderVal("attachment; filename=\"" + getFileName() + "\"");
                        String fileSuffix = getFileName().substring(getFileName().lastIndexOf(".")+1);
                        child.setContentFromBytes(stream, MIMEType.get(fileSuffix), MIMEEntity.ENC_IDENTITY_BINARY);
                        stream.close();
                    }
            }
        } catch (NotesException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
 
    /**
     * Saves the RichTextItem we're working on by saving the Document that
     * contains it.
     */
    public boolean save () throws IOException {
        // a convenience method to save the Document we're working on
        // (we could have done this with the flush() method, but that could
        // cause unexpected results if this OutputStream is wrapped in
        // another Stream or Writer that auto-flushes)
        try {
            return rtitem.getParent().save();
        } catch (NotesException e) {
            // turn our NotesExceptions into IOExceptions
            throw new IOException(e.getMessage());
        }
    }
 
    /**
     * Writes an array of bytes to the RichTextItem (converting it first to a String).
     *
     * @param  b        an array of bytes
     */
    public void write (byte[] b) throws IOException {
        if (rtitem==null && body!=null) {
            super.write(b);
        }else {
            write(new String(b));
        }
    }
 
    /**
     * Writes len bytes from a byte array to the RichTextItem, starting at offset off
     * (converting it first to a String).
     *
     * @param  b        an array of bytes
     * @param  off      the start offset in the data
     * @param  len      the number of bytes to write
     */
    public void write (byte[] b, int off, int len) throws IOException {
        if (rtitem==null && body!=null) {
            super.write(b, off, len);
        }else {
            write(new String(b, off, len));
        }
    }
 
    /**
     * Writes a single byte to the RichTextItem (converting it first to a String).
     *
     * @param  b        a single byte
     * @throws NotesException
     */
    public void write (byte b) throws IOException, NotesException {
        if (rtitem==null && body!=null) {
            if (count<MAX_BUF) {
                buffer[count]=b;count++;
            }else {
                flush2Stream(buffer);
                buffer[0]=b;count=1;
            }
            //stream.write(buffer);
        }else {
            write(String.valueOf((char)b));
        }
    }
 
    private void flush2Stream(byte[] bytesIn) throws NotesException {
        // TODO Auto-generated method stub
        //optimization for memory operation
        if (count+1<MAX_BUF) {
            //copy when buffer isn't full
            byte[] buff=Arrays.copyOf(bytesIn, count);
            stream.write(buff);
        }
        else {
            stream.write(bytesIn);
        }
        count=0;
        //Arrays.fill( bytesIn, (byte)0 );
    }

    /**
     * Writes a String to the RichTextItem.
     *
     * @param  str      a String to write
     */
    public void write (String str) throws IOException {
    
        try {
            // make sure we have a RichTextItem to write to
            if (rtitem == null)
                throw new IOException("The RichTextItem that you are trying to write to is null (maybe close() was called)");
        
            // and make sure we have a String to write
            if (str == null)
                return;
        
            // if we're not converting linefeeds, all we have to do is write
            // the String; otherwise, we'll need to tokenize it and replace
            // \r and \n with addNewLine calls (making sure to call it only
            // once for Windows \r\n linefeed combinations)
            if (!convertLF) {
                rtitem.appendText(str);
            } else {
                boolean wroteCR = false;
                String token = "";
                StringTokenizer st = new StringTokenizer(str, "\r\n", true);
            
                while (st.hasMoreTokens()) {
                    token = st.nextToken();
                    if (token.equals("\r")) {
                        rtitem.addNewLine(1);
                        wroteCR = true;
                    } else if (token.equals("\n")) {
                        if (!wroteCR)
                            rtitem.addNewLine(1);
                        wroteCR = false;
                    } else {
                        rtitem.appendText(token);
                        wroteCR = false;
                    }
                }
            }
        } catch (NotesException e) {
            // if we got a NotesException writing to the RichTextField,
            // turn it into an IOException and throw it (this way our
            // OutputStream is only throwing IOExceptions, which is
            // fairly standard)
            throw new IOException(e.getMessage());
        }
    }
 
    /**
     * Writes an entire InputStream to the RichTextItem (converting its contents to a String).
     *
     * @param  in       an InputStream
     * @throws NotesException
     */
    public void write (InputStream in) throws IOException, NotesException {
        int howManyBytes;
        byte[] bytesIn = new byte[2048];
        while ((howManyBytes = in.read(bytesIn)) >= 0) {
            stream.write(bytesIn);
            Arrays.fill( bytesIn, (byte)0 );
        }
        flush();

/*        while ((howManyBytes = in.read(bytesIn)) >= 0)
            write(bytesIn, 0, howManyBytes);
*/
        }
 
    /**
     * Writes a String to the RichTextItem, followed by a RichText newline.
     *
     * @param  str      a String to write
     */
    public void writeLine (String str) throws IOException {
        write(str);
        try {
            rtitem.addNewLine(1);
        } catch (NotesException e) {
            // turn our NotesExceptions into IOExceptions
            throw new IOException(e.getMessage());
        }
    }
 
    /**
     * Writes an attachment or object to the RichTextItem, using the parameters that are
     * called for in the NotesRichTextItem.embedObject() method (see this method in the
     * Notes Designer Help for more information about the parameters and usage).
     *
     * @param  type     either EmbeddedObject.EMBED_ATTACHMENT,
     *                          EmbeddedObject.EMBED_OBJECT, or
     *                          EmbeddedObject.EMBED_OBJECTLINK
     * @param  objClass     the name of an application (for EmbeddedObject.EMBED_OBJECT)
     *                              or null
     * @param  source       the name of the file to attach or link to
     * @param  name     either a name by which you want to refer to the EmbeddedObject,
     *                          or null.
     * @return  EmbeddedObject      a Notes EmbeddedObject reference to the file that
     *                                          was attached
     */
    public EmbeddedObject writeAttachment (int type, String objClass, String source, String name) throws IOException {
        try {
            return rtitem.embedObject(type, objClass, source, name);
        } catch (NotesException e) {
            // turn our NotesExceptions into IOExceptions
            throw new IOException(e.getMessage());
        }
    }
 
    /**
     * Changes the RichTextStyle of the text that will be written to the underlying
     * RichTextItem. Note that this only affects data that is written after this method
     * is called, not data that has already been written.
     *
     * @param  style        a Notes RichTextStyle that should be used to format
     *                          data that is written to this stream
     */
    public void setStyle (RichTextStyle style) throws IOException {
        try {
            rtitem.appendStyle(style);
        } catch (NotesException e) {
            // turn our NotesExceptions into IOExceptions
            throw new IOException(e.getMessage());
        }
    }
 
    /**
     * Changes the RichTextParagraphStyle of the text that will be written to the underlying
     * RichTextItem. Note that this only affects data that is written after this method
     * is called, not data that has already been written.
     *
     * @param  style        a Notes RichTextParagraphStyle that should be used to format
     *                          data that is written to this stream
     */
    public void setParagraphStyle (RichTextParagraphStyle pstyle) throws IOException {
        try {
            rtitem.appendParagraphStyle(pstyle);
        } catch (NotesException e) {
            // turn our NotesExceptions into IOExceptions
            throw new IOException(e.getMessage());
        }
    }

    @Override
    public void write(int b) throws IOException {
        try {
            write((byte)b);
        } catch (NotesException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
фух.. устал копипастить :)
заключительный аккорд
Java:
                Document doc=db.createDocument();
                doc.replaceItemValue("form", BATCH_FORM);
                RichTextOutputStream rtos = new RichTextOutputStream("Body", doc);
                rtos.setFileName("out.docx");
                //report will close output
                report.process(context, rtos);
форма - по вкусу...
[doublepost=1493393153][/doublepost]
if (count<MAX_BUF) {
buffer[count]=b;count++;
}else {
flush2Stream(buffer);
buffer[0]=b;count=1;
}
тупой момент, учитывая что я обнуляю count ;) быстрофикс
Java:
if (count>=MAX_BUF) flush2Stream(buffer);
buffer[count]=b;count++;
 
  • Нравится
Реакции: Vertigo
K

Kee_Keekkenen

есть нежелание что-то прописывать руками
это не понято.. чем это от написания кода отличается ?!.. все одно библиотеки должны где-то лежать, от проекта к проекту их состав может меняться, чтобы не плодить файло-помойки, репозитарий (локальный или серверный) все хранит в единственном числе..
создаешь проект под мавеном и горя не знаешь..

м-да.. я уже успел забыть что такое лотус.. хотя ничего идеального не бывает.. сейчас тоже создаю pdf через itext5 файлы там только xsl и css, остальное стримы и байт-массивы.. вроде все более менее, но вот данные частично имеют html представление - типо ричтекстовый редактор их так сохраняет, и основной затык это картинки, потому как часть из них копипастит пользователем, а часть - аттачится.. а поскольку pdf создается на основе сформированного html, то на горизонте проблемы - как это добро прилепить к xslt, которое формирует окончательный html перед созданием pdf.. буду после праздников этим геморром заниматься
 
Последнее редактирование модератором:

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 933
609
BIT
177
затык это картинки, потому как часть из них копипастит пользователем, а часть - аттачится.. а поскольку pdf создается на основе сформированного html, то на горизонте проблемы - как это добро прилепить к xslt, которое формирует окончательный html перед созданием pdf
xslt вполне себе есть base64
с FOP я такое проделывал
 
K

Kee_Keekkenen

пока еще до этого не дошел.. с xslt проблем-то не будет, главное, чтобы itext все это понял..
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 933
609
BIT
177
Теперь детали по работе со стримами
движок принимает на вход InputStream , и на выход OutputStream - это я уже упомянул, а вот тонкости рассказал только про OutputStream (что он закрывается)
с InputStream происходит то же ;) - это не удивительно (нормально)
но тут есть момент - если мы дали на вход стрим их аттача и он закрылся, но поторное обращение даст исключение и...
нам надо заново получать этот стрим
почему акцент - шаблон может употребляться многократно (на то он и шаблон)
Java:
    public InputStream getIn(String key) throws NotesException {
        Document doc=tmplView.getDocumentByKey(key);
        if (doc==null) {
            //default template document
            doc=defdoc;
            key=DEF_FUSION;
        }
        if (doc!=null) {
            if (map.containsKey(key))return getIn(map.get(key));
            map.put(key,doc);
            //return first attachment stream
            return getIn(doc);
        }
        return null;
    }
    
    @SuppressWarnings("unchecked")//Vector 2 EmbeddedObject
    private InputStream getIn(Document doc) throws NotesException {
        Vector<EmbeddedObject> objs;//=doc.getEmbeddedObjects();
        RichTextItem body =
            (RichTextItem)
            doc.getFirstItem("Body");
        objs=body.getEmbeddedObjects();
        InputStream in=objs.elementAt(0).getInputStream();
        return in;
    }
    public void recycle() throws NotesException {
        for(Entry<String, Document> e:map.entrySet()) {
            e.getValue().recycle();
        }
        tmplView.recycle();
        db.recycle();
        ses.recycle();
    }
по поняным причинам - в коде есть recycle()
 
K

Kee_Keekkenen

прикольно.. какой-то "противоречивый" код.. зачем defdoc, если он может быть null ?
какой практический результат дает recycle() ?
а body и objs разве не убиваемые (в смысле нельзя убивать)?
один точно должен быть убиваемым, может и оба (ресайклить так все.. что можно)
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 933
609
BIT
177
прикольно.. какой-то "противоречивый" код.. зачем defdoc, если он может быть null ?
какой практический результат дает recycle() ?
а body и objs разве не убиваемые (в смысле нельзя убивать)?
один точно должен быть убиваемым, может и оба (ресайклить так все.. что можно)
ну код не вычищенный... и это нормально ;), но данный кусок - вполне нормальный (с моей т.з.)
defdoc - очевидно, не нашел по ключу - используем предопределенный, ключ - однозначная строка (т.е. не шаблон) и стало быть - его может не быть во вьюшке (не понимаю - что удивило). defdoc просто может быть не инициализирован (подчиняясь правилам нотусятины) - только тогда должны поручить исключение, в вызывающем коде по null
recycle java объектов в домино - способ не получить утечку памяти!, ибо - они (доминошные объекты) мапятся на на Сишные (и здесь странно слышать удивление)
doc - получаем по шаблону "повторного использования", т.е. из хэша (и это видно по коду) и если его recycle - то он вполне себе снесет и стрим ;) тоже касается и EmbeddedObject и придется повторно его получать из БД (что накладно)
а вот стрим, являясь чисто java объектом - будет подчиняться правилам jvm
вызывать recycle в самом классе или кастылировать финализацию - выстрел в ногу, в самый неподходящий момент. И вот почему - время жизни jvm объектов, при вызове из агента, не заканчивается завершением агента, агент просто попытается эмулировать System.exit (именно эмулировать). Финализация произойдет, но с ощутимой задержкой (код уже пройдет дальше)
В такой ситуации - реальный шанс получить блокировку нек. объектов, кот. еще не вычищены, с непредсказуемыми последствиями.
Т.е. recycle должен вызываться осмысленно и в строго опред. местах, подобрать подходящий момент - нек. усилия требует ;)
[doublepost=1493890263,1493889743][/doublepost]ЗЫЖ если есть правки (обоснованные) кода - это всегда +
 
K

Kee_Keekkenen

как бы, defdoc не может(в смысле должен) быть null, т.к. это подразумевает его наличие вообще, если, конечно, для каких-то случаев defdoc в принципе отсутствует как таковой.. а то так некрасиво в метод заведомый null пихать..

про recycle хотел услышать, что это реально работает.. лет 5 назад, тоже подобное писал, однако память не освобождалась, хотя я не проверял на длительном отрезке времени.. просто была такая конструкция, что один агент по циклу запускал другие агенты, где все что можно ресайклилось и каждый ел прилично памяти и ее не хватало.. а чтобы хватало, то после каждого агента был еще агент, который принудительно вызывал гарбач-коллектор и это реально память чистило..
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 933
609
BIT
177
как бы, defdoc не может(в смысле должен) быть null, т.к. это подразумевает его наличие вообще,
нотусевый объект в принципе может быть недоступен (пример - права) и получим null
а вот что делать?! "принимать решение" в классе - некрасиво, не тот уровень в приложении..., как и высыпать в исключение в нем (из-за доступа)
про recycle хотел услышать, что это реально работает.. лет 5 назад
он чистит Сишные хэндлы, а не память в jvm!
и никакой GC не спасет, если память засрана вне jvm
вашу ситуацию описал выше - агент вызывает (вернее агент помечает для удаления объекты и сдыхает, далее - GC сам решает) finalize , но со значительной задержкой!
[doublepost=1493986940,1493985694][/doublepost]возвращаясь к особенностям xdocreport...
движок "общается" с ФС и это требует доступа от агента!
upload_2017-5-5_15-21-13.png
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!