• 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

    За 3 месяца вы пройдете путь от начальных навыков работы с SQL-запросами к базам данных до продвинутых техник. Научитесь находить уязвимости связанные с базами данных, и внедрять произвольный SQL-код в уязвимые приложения.

    На последнюю неделю приходится экзамен, где нужно будет показать свои навыки, взломав ряд уязвимых учебных сайтов, и добыть флаги. Успешно сдавшие экзамен получат сертификат.

    Запись на курс до 25 апреля. Получить промодоступ ...

Унификация разработки

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
Речь пойдет больше про java и xpages
Что хочется:
- писать код и тестировать его во внешних ИДЕ (дизайнер сильно убогий по разработке java/js...)
- при переносе в дизайнер минимально изменять код
- кроссплатформа

про Team Development знают (полагаю) все, там есть ODP (On Disk Project) т.е. создавая приложение можно ему назначить его отображение на папку, а уже её синхронить и с nsf и с git (как вариант)
Засада состоит в том, что классы домины привязаны к нативным либам, что создает массу нецдобств и отсутствие переносимости (если рарабаывать одновременно в дизайнере и ИДЕ, на др. платформе)

Вариант с IIOP ну очень горбатый. Предлагаю следующую модель:
- пишем REST для доступа в сущностям, возможно использовать
- делаем финт с авторизацией (уже описывал) - создавая LtpaToken, через страницу в публичным доступом и шифрованием
- обращение к сущностям получаем в виде JSON
- к внешней ИДЕ надо будет прикрутить (в домине оно и так есть)
немного кода xAgent_token.xsp:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
    <xp:this.beforePageLoad><![CDATA[#{javascript:try {
var url = context.getUrl();
var host = url.getHost();
var domain=host.match(/\..*/)[0];
var response=facesContext.getExternalContext().getResponse();

//var token=paramValues.get("token").toString();
//var rUrl=paramValues.get("url").toString();
var user_enc = context.getUrlParameter('id');
print("::xAgent_token::id:" + user_enc);
var user=decrypt(base64_decode(user_enc));
print("::xAgent_token::User:" + user);
/* var httpURL = database.getHttpURL();
var dbUrl= httpURL.replace("http://", "https://").match(/(.+)\?/)[1];
print("url:"+dbUrl);
*/
  var generated=LtpaGenerator(user);

//var header="LtpaToken=" + token + "; domain=" + domain + "; path=/";

//response.setHeader("Set-Cookie", header);
//facesContext.getExternalContext().redirect(rUrl);
  var externalContext:javax.faces.context.ExternalContext = facesContext.getExternalContext();
  var response:javax.servlet.http.HttpServletResponse = externalContext.getResponse();
  response.setHeader("Cache-Control", "no-cache");
  response.setDateHeader("Expires", -1);
  var externalContext:javax.faces.context.ExternalContext = facesContext.getExternalContext();
  var response:javax.servlet.http.HttpServletResponse = externalContext.getResponse();
  response.setHeader("Cache-Control", "no-cache");
  response.setDateHeader("Expires", -1);
  var gVars=getVars();
  print("::xAgent_token::token:"+generated);
  response.setHeader("Set-Cookie", "LtpaToken=" + generated + "; domain="+ gVars.domain + "path=/");
  //response.setContentType("text/html;charset=UTF-8");
  var writer:java.io.PrintWriter = response.getWriter();
  writer.write(generated);

} catch(e) {
        _dump(e);
}
}]]></xp:this.beforePageLoad>

    <xp:this.resources>
        <xp:script src="/SSJSUtils.jss" clientSide="false"></xp:script>
    </xp:this.resources>
</xp:view>
либы уже выкладывал, если нужно что-то довыложить - спрашивайте
суть проста - генерим токен при вызове страницы, ответом прописываем куки на запрашивающую сторону
следом можем уже вызывать REST или DAS
Java:
import com.ibm.commons.util.io.json.JsonException;
import com.ibm.commons.util.io.json.JsonJavaFactory;
import com.ibm.commons.util.io.json.JsonParser;
import org.apache.commons.codec.binary.Base64;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;

public class DAS {
    //... здесь поля, кот. зависят от приложения target - это адрес "...xAgent_token.xsp?id=" + encBase64 (см. authorize)
    private static final JWT jwt = new JWT();
    private static final String encrypted = jwt.encrypt(userName,key);
    private static final String encBase64=new String(Base64.encodeBase64(encrypted.getBytes()));
    static{TrustAllCertificates.install();}

    private static List<String> cookies;

    public static InputStream request2URL(String target) throws IOException {

        URL url=new URL(target);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (cookies!=null)
            for (String cookie : cookies) {
                conn.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
            }

        InputStream res = null;
        if (conn.getResponseCode() == 200) {
            System.out.println("OK");
            res= conn.getInputStream();
            if (cookies==null)cookies = conn.getHeaderFields().get("Set-Cookie");
            if (cookies!=null) {
                for (String el : cookies) {
                    System.out.println(el);
                }
            }

        }else{
            System.out.format("Request status %d -> %s\n",conn.getResponseCode(),conn.getResponseMessage());
        }
        return res;
    }
    public static String request2URLString(String target) throws IOException {
        String res="";
        URL url=new URL(target);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (cookies!=null)
            for (String cookie : cookies) {
                conn.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
            }

        if (conn.getResponseCode() == 200) {
            System.out.println("OK");
            res= result2String(conn);
            if (cookies==null)cookies = conn.getHeaderFields().get("Set-Cookie");
            if (cookies!=null) {
                for (String el : cookies) {
                    System.out.println(el);
                }
            }

        }else{
            System.out.format("Request status %d -> %s\n",conn.getResponseCode(),conn.getResponseMessage());
        }
        return res;
    }

    private static String result2String(HttpURLConnection conn) throws IOException {
        StringBuilder res = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String line = "";
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
            res.append(line);
        }
        reader.close();
        return res.toString();
    }

    public static void authorize() throws IOException {
        cookies=null;
        URL url=new URL(target+encBase64);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (conn.getResponseCode() == 200) {
            result2String(conn);
            cookies = conn.getHeaderFields().get("Set-Cookie");
            for (String el : cookies) {
                System.out.println(el);
            }
        }
    }
    //https://stackoverflow.com/questions/40917681/in-xpages-how-do-you-get-the-post-body-from-a-rest-call
    //jar: https://jar-download.com/?detail_search=g%3A%22com.ibm.sbt%22+AND+a%3A%22com.ibm.commons%22+AND+v%3A%229.0.0%22&a=com.ibm.commons
    public static void main(String[] args) throws IOException, JsonException {
        authorize();
        //String res=request2URLString(serverURL+dbPart+"/PDFTemplates"+viewJsonPart);
        String reqnames=request2URLString(serverURL+dbPart+"/restCustom.xsp/customJSONcat");
        List<Map<String, Object>> names = (List<Map<String, Object>>)JsonParser.fromJson(JsonJavaFactory.instanceEx, reqnames);;
        for(Map<String, Object> nameobj:names) {
            String nameconf = (String) nameobj.get("name");
            String req = request2URLString(serverURL + dbPart + "/restCustom.xsp/customJSONfilter?key="+nameconf);
            System.out.print("*********** "+nameconf+" ");
            //"https://mail1.castrolcis.com/templates/qpassport.nsf/restCustom.xsp/customJSONfilter?key=Neuhof,France"
            //InputStreamReader isR = new InputStreamReader(request2URL(serverURL+dbPart+"/restCustom.xsp/customJSONfilter?key=Neuhof,France"));
            //JsonJavaObject jsonObj = (JsonJavaObject) JsonParser.fromJson(JsonJavaFactory.instanceEx, isR);
            //List<Map<String, Object>> arr
            List<Map<String, Object>> result = (List<Map<String, Object>>) JsonParser.fromJson(JsonJavaFactory.instanceEx, req);
            for (Map<String, Object> map : result) {
                String rowmap = (String) map.get("rowmap");
                String name = (String) map.get("name");
                String region = (String) map.get("region");
                boolean isID = (Boolean) map.get("isID");
                System.out.format("********************\nname:%s\nregion:%s\nrowmap:\n", name, region);
                new PDFDBReadConfig.TestTable(region, isID, rowmap.split(";"));
                for (String r : rowmap.split(";")) {
                    System.out.format("\t%s\n", r);
                }
            }
        }
    }
}
ключ (key)для шифрования используется при отправке имени пользователя, он должен соответствовать таковому на сервере. Json парсер - это как-раз из com.ibm.commons.util.io.json
в main вызывается autorize() и после - запрос к домине (токен передается с куками)
В домине будет использован тот же JSON хоть из java хоть из JS
Т.е. формат и логика разработки будут одинаковы в ИДЕ и дизайнере
 
Последнее редактирование:

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
еще момент - есть получение данных из вьюшки типа формата JSON
ниже кусок получения значений из вьюшки с отображением мультивэлью как несколько строк
Java:
private static final String viewJsonPart="?ReadViewEntries&OutputFormat=JSON";
....
        String reqnames=request2URLString(serverURL+dbPart+"/"+TMPL_VIEW+viewJsonPart);
        Map<String, Object> viewmap = (Map<String, Object>) JsonParser.fromJson(JsonJavaFactory.instanceEx, reqnames);
        List<JsonObject> entries= (List<JsonObject>) viewmap.get("viewentry");
        //List<Map<String, Object>> names = (List<Map<String, Object>>)JsonParser.fromJson(JsonJavaFactory.instanceEx, reqnames);
        for(JsonObject entry:entries) {
            System.out.println(entry.getJsonProperty("entrydata"));// +"\n"+ entry.getJsonProperty("entrydata").getClass().getName());
            List<JsonObject>list= (List<JsonObject>) entry.getJsonProperty("entrydata");
            System.out.println(list.get(0).getJsonProperty("text"));
            JsonObject jo=(JsonObject)list.get(2).getJsonProperty("textlist");
            if (jo!=null) {
                List<JsonJavaObject> arrJsonJavaObject = (List<JsonJavaObject>) jo.getJsonProperty("text");
                System.out.println(arrJsonJavaObject.get(0).get("0"));
/*
                //only one element
                for (JsonJavaObject jjo : arrJsonJavaObject) {
                    System.out.println(StringEscapeUtils.unescapeJava(jjo.toString()));
                }
*/
 
Последнее редактирование:

savl

Lotus Team
28.10.2011
2 597
310
BIT
179
@lmike а автосборку еще не рассматривал? Я вот смотрю в эту сторону, причем для классики...
есть такое:
Я даже просто пробовал делать командами через батник, но операция пока полуручная... И надо многое продумать...
Там еще был проект с участием Ant сборщика.
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
Я вот смотрю в эту сторону, причем для классики...
пока нет и меня смущает необходимость нативных либ домины
по ссылке - это что-то экстримальное ;) - патч на класс
цель моих изысканий - получение рабочего варианта (без нотусевых сущностей), кот. я почти 1-1 перенесу в домину, и для теста нужен только доступный сервер домины
по сути этот подход очень напоминает ODA, но нет необходимости в доп. OSGi плаге на сервере
в тек. состоянии я уже спокойно обращаюсь БД, через http, на домине будет также. Накладные расходы будут нивелированы отсут. recycle для нотусевых объектов и необходимости их перетаскивания в память и "обратно"...
 
Последнее редактирование:

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
мну эти фичи понра
но пока не решился на ФП8, на основном сервере
 

savl

Lotus Team
28.10.2011
2 597
310
BIT
179
ну это я как вариант, а вот автосборку можно запустить и простой командой. Но для этого нужен дизайнер где-то, да еще и старт без запроса пароля... а значит винда, которую ты не перевариваешь...
в целом, идея то хорошая, мне самому надо сделать что-то вроде CI/CD для Domino, да еще и с контролем версий.
Но на DAS + Web + xpage я даже не надеюсь, в компаниях с большим уровнем иерархии такие идеи просто застревают :(
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
Но для этого нужен дизайнер где-то, да еще и старт без запроса пароля... а значит винда, которую ты не перевариваешь...
не то чтобы не перевариваю, она реально пропихивается везде, хотя присутствуют сложности в управлении и настройке, особенно для разработки
пример Сделаем Windows медленнее! Часть первая: файловый доступ
хватануть это можно на ровном месте и подобное задалбывает... я не осущ. подобных масштабов разработок (даже близко) , но куча тупок и ненужной мне активности, винды, мешает сильно
Инструменты - я легко разверну ч-л, от виртуалки до контейнеров, в винде с этим все плохо (куча кастылей и стороннего софта)
CI/CD для Domino, да еще и с контролем версий.
очень близко и разаботку вести в сторонней ИДЕ (я в Idea делаю), сборку в nsf - придется дизайнер дергать...
Но на DAS + Web + xpage я даже не надеюсь
собрать простую демонстрацию и показать начальству, может подействует ;)
сделать демку из моего поста про интеграцию с ОнлиОфис - наглядное совместное редактирование доков (из домины)...
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
вот интересно -
серверный дизайнер умеет так?
 

savl

Lotus Team
28.10.2011
2 597
310
BIT
179
@lmike да. Только по факту, это дизайнер на сервере просто.
То есть ставишь клиент на сервер и через командную строку на сервере запускаешь.
Нашел пару минусов:
1. Клиент на сервере должен запускаться без пароля, это важно.
2. Результирующий проект nsf/ntf кладется в папку Data клиента, всегда в корень !!!11 никаких вложенных папок.
3. Если файл nsf/ntf уже такой есть, то задача не отрабатывает.
4. Логи гавно, без комментариев.
5. Массовый билд не работает, либо я не смог его нормально запустить. Лучше на один проект - один файл и в цикле делать.
6. Имя шаблона для базы не задать... То есть Replace/Refresh потом делать все равно вручную.

По сути тот проект/плагин для развертывания или его вариант через Ant, реализован через этот же механизм.
Там по большей части эти минусы решены.
 
  • Нравится
Реакции: lmike и Vertigo

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
натолкнулся на свой же сервак, кот. принимает ssl DH 2048...
для обывательской jvm 1.6 это непреодолимый барьер
а вот jvm домины (у меня IBM Domino (r) Server (Release 9.0.1FP7 for UNIX) кушает это нормально (ИБМ, видать, запилило поддержку, учитывая расширенную поддержку от оракла)
сообщение из Idea при jvm 1.6 такое
javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair
переключение на 1.8 лечит, но не утешает, т.к. хотелосьбы тестировать для "одинаковых" условий
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
изменения для JSON и его обработки унификация по типу в колонках. Так получается, что при занечении в колонку поля мультивалью (текстовое) может присутствовать как textlist так и text, пример - 5-я колонка:
JSON:
{
"@timestamp": "20181211T153819,72Z",
"@toplevelentries": "3",
"viewentry": [
{
"@position": "1",
"@unid": "8CF66B658645CA2B432583600045A678",
"@noteid": "498E",
"@siblings": "3",
"entrydata": [
{
"@columnnumber": "0",
"@name": "unid",
"text": {
"0": "8CF66B658645CA2B432583600045A678"
}
},
{
"@columnnumber": "1",
"@name": "name",
"text": {
"0": "test"
}
},
{
"@columnnumber": "2",
"@name": "lastModified",
"datetime": {
"0": "20181211T163247,58+03"
}
},
{
"@columnnumber": "3",
"@name": "created",
"datetime": {
"0": "20181211T154046,00+03"
}
},
{
"@columnnumber": "4",
"@name": "description",
"text": {
"0": ""
}
},
{
"@columnnumber": "5",
"@name": "unids",
"text": {
"0": "A84402C33F67FC4F4325835F003B1265"
}
}
]
},
{
"@position": "2",
"@unid": "A33B3E00318EE5AB4325833F003D3F05",
"@noteid": "4622",
"@siblings": "3",
"entrydata": [
{
"@columnnumber": "0",
"@name": "unid",
"text": {
"0": "A33B3E00318EE5AB4325833F003D3F05"
}
},
{
"@columnnumber": "1",
"@name": "name",
"text": {
"0": "Common Price"
}
},
{
"@columnnumber": "2",
"@name": "lastModified",
"datetime": {
"0": "20181108T140934,52+03"
}
},
{
"@columnnumber": "3",
"@name": "created",
"datetime": {
"0": "20181108T140858,29+03"
}
},
{
"@columnnumber": "4",
"@name": "description",
"text": {
"0": ""
}
},
{
"@columnnumber": "5",
"@name": "unids",
"textlist": {
"text": [
{
"0": "6EA484D8E35C04654325833F003B9672"
},
{
"0": "9C0DA58F338990614325833F003B9683"
},
{
"0": "A7ED3FF264150C3D4325833F003B9697"
},
{
"0": "02F85C073BEEB34C4325833F003B96AB"
},
{
"0": "C9C3A58E8AF0563D4325833F003B96C3"
},
{
"0": "720CFFA1A3FE1C454325833F003B96D2"
},
{
"0": "CAACAF77394DE5ED4325833F003B96DA"
}
]
}
}
]
},
{
"@position": "3",
"@unid": "BB54B3782CBD245C432582CD005D72CD",
"@noteid": "A6E",
"@siblings": "3",
"entrydata": [
{
"@columnnumber": "0",
"@name": "unid",
"text": {
"0": "BB54B3782CBD245C432582CD005D72CD"
}
},
{
"@columnnumber": "1",
"@name": "name",
"text": {
"0": "Main Profile"
}
},
{
"@columnnumber": "2",
"@name": "lastModified",
"datetime": {
"0": "20181210T210309,75+03"
}
},
{
"@columnnumber": "3",
"@name": "created",
"datetime": {
"0": "20180717T200042,37+03"
}
},
{
"@columnnumber": "4",
"@name": "description",
"text": {
"0": "Accumulate all discounts"
}
},
{
"@columnnumber": "5",
"@name": "unids",
"textlist": {
"text": [
{
"0": "E813A08341E613124325835F005A8B9E"
},
{
"0": "720CFFA1A3FE1C454325833F003B96D2"
}
]
}
}
]
}
]
}
для обработки изменил класс:
Java:
package com.setralubs;

import com.ibm.commons.util.io.json.*;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.IteratorUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

public class JSON2DB {
    static final String viewJsonPart="?ReadViewEntries&OutputFormat=JSON";
    private List<String> cookies;
    private final String target;
    private final String encBase64;
    String LIST_SEP = ";";
    private Predicate<String> nodetype = node->{return !node.startsWith("@");};

    public JSON2DB(String target, String key, String userName) throws IOException {
        TrustAllCertificates.install();
        this.target = target;
        JWT jwt = new JWT();
        encBase64=new String(Base64.encodeBase64(jwt.encrypt(userName, key).getBytes()));
        authorize();
    }
    public void authorize() throws IOException {
        cookies=null;
        URL url=new URL(target+encBase64);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (conn.getResponseCode() == 200) {
            //read response from authPage
            result2String(conn);
            cookies = conn.getHeaderFields().get("Set-Cookie");
/*
            for (String el : cookies) {
                System.out.println(el);
            }
*/
        }
    }

    private String result2String(HttpURLConnection conn) throws IOException {
        StringBuilder res = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String line = "";
        while ((line = reader.readLine()) != null) {
            //System.out.println(line);
            res.append(line);
        }
        reader.close();
        return res.toString();
    }

    private String result2String(InputStream is) throws IOException {
        StringBuilder res = new StringBuilder();
        if (is!=null) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            String line = "";
            while ((line = reader.readLine()) != null) {
                //System.out.println(line);
                res.append(line);
            }
            reader.close();
        }else{
            System.err.println("input stream is null");
        }
        return res.toString();
    }

    public String request2URLString(String target) throws IOException {
        return result2String(request2URL(target));
    }

    public InputStream request2URL(String target) throws IOException {

        URL url=new URL(target);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (cookies!=null)
            for (String cookie : cookies) {
                conn.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
            }

        InputStream res = null;
        if (conn.getResponseCode() == 200) {
            //System.out.println("OK");
            res= conn.getInputStream();
            if (cookies==null)cookies = conn.getHeaderFields().get("Set-Cookie");
        }else{
            System.out.format("Request status %d -> %s\n",conn.getResponseCode(),conn.getResponseMessage());
        }
        return res;
    }

    @SuppressWarnings("unchecked")
    public List<List<Object>> getEntries(String jsonEntries, List<String> colNames, List<String> colTypes) throws JsonException {
        if (jsonEntries.isEmpty())return null;
        Map<String, Object> viewmap = (Map<String, Object>) JsonParser.fromJson(JsonJavaFactory.instanceEx, jsonEntries);
        List<JsonObject> entries= (List<JsonObject>) viewmap.get("viewentry");
        //List<Map<String, Object>> names = (List<Map<String, Object>>)JsonParser.fromJson(JsonJavaFactory.instanceEx, reqnames);
        if (entries==null) return null;
        //get first entry
        int i;List<JsonObject> list =((List<JsonObject>) entries.get(0).getJsonProperty("entrydata"));
        /* entrydata node example
         "entrydata": [
         {
         "@columnnumber": "0",
         "@name": "pUNID",
         "text": {
         "0": "6EA484D8E35C04654325833F003B9672"
         }
         ]
         */
        if (colNames==null) colNames=new ArrayList<String>();else colNames.clear();
        if (colTypes==null) colTypes=new ArrayList<String>(); else colTypes.clear();
        for(i = 0; i<list.size(); i++) {
            List<String> colList = IteratorUtils.toList(list.get(i).getJsonProperties());
            // see node example
            colNames.add((String) list.get(i).getJsonProperty("@name"));
            colTypes.add("unknown");
            for(String node:colList){if(!node.startsWith("@")){colTypes.set(i,node);break;}};
            //System.out.format("col:%d; name:%s; type:%s\n",i,list.get(i).getJsonProperty("@name"),colList.get(1));
        }
        List<List<Object>> entriesValues=new ArrayList<>();
        for(JsonObject entry:entries) {
            //System.out.println(entry.getJsonProperty("entrydata"));// +"\n"+ entry.getJsonProperty("entrydata").getClass().getName());
            list = (List<JsonObject>) entry.getJsonProperty("entrydata");
            List<Object> colValues=new ArrayList<>();
            //by columns
            for(i = 0; i<list.size(); i++) {
                JsonObject jo = (JsonObject) list.get(i);
                Object obj=null;
                JsonJavaObject jjo=null;
                jjo = (JsonJavaObject) jo.getJsonProperty(colTypes.get(i));
                String coltype= (String) IteratorUtils.toList(jo.getJsonProperties()).stream().
                filter(nodetype).findFirst().get();
                switch (coltype) {
                    case "text":
                        if (jjo!=null) {
                            obj = jjo.get("0").toString();
                        }
                        break;
                    case "number":
                        if (jjo!=null) {
                            obj = jjo.get("0").toString();
                        }
                        break;
                    case "datetime":
                        if (jjo!=null) {
                            obj = jjo.get("0").toString();
                        }
                        break;
                    case "textlist":
                        //(JsonObject) list.get(i)
                        jo = (JsonObject) jo.getJsonProperty(coltype);
                        if (jo != null) {
                            List<JsonJavaObject> arrJsonJavaObject = (List<JsonJavaObject>) jo.getJsonProperty("text");
                            List<String> buf=new ArrayList();
                            for(JsonJavaObject el:arrJsonJavaObject){
                                buf.add(el.get("0").toString());
                            }
                            //text = String.join(LIST_SEP,buf);//(String) arrJsonJavaObject.get(0).get("0");
                            obj=buf;
                        }else {//try text
/*
                            jjo = (JsonJavaObject) list.get(i).getJsonProperty("text");
                            if (jjo!=null) {
                                text = jjo.get("0").toString();
                            }
*/
                        }
                        break;
                }

                //fill only text and texllist types
/*
                JsonJavaObject jjo= (JsonJavaObject) jo.getJsonProperty("text");
                String text="";
                if (jjo!=null) {
                    text = (String) jjo.get("0");
                    //System.out.format("col:%d; \"%s\"\n", i, jjo.get("0"));
                }else{
                    jo = (JsonObject) list.get(i).getJsonProperty("textlist");
                    if (jo != null) {
                        List<JsonJavaObject> arrJsonJavaObject = (List<JsonJavaObject>) jo.getJsonProperty("text");
                        text= (String) arrJsonJavaObject.get(0).get("0");
                    }
                }
*/
                colValues.add(obj);
            }
            entriesValues.add(colValues);
        }
        return entriesValues;
    }
}
и еще обработка уровнем выше
Java:
package com.setralubs;

import com.ibm.commons.util.io.json.JsonException;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;

import static com.setralubs.AuthToken.*;

public class DataFromDB {
    protected String LOOKUP_VIEW;
    final String MAX_COUNT="&Count=2000";
    final JSON2DB json2DB;
    final String SEARCH_FROM = "&StartKey=%s";
    List<String> colNames;
    List<String> colTypes;

    public DataFromDB() throws IOException {
        json2DB=new JSON2DB(target,key,userName);
    }
    public List<List<Object>> getEntries(final String key) throws IOException, JsonException {
        colNames = new ArrayList<String>();
        colTypes = new ArrayList<String>();
        URLEncoder.encode("", "UTF-8");
        String skey="";
        List<List<Object>> result=null;
        if (!key.isEmpty()) skey=String.format(SEARCH_FROM+"&Count=1", URLEncoder.encode(key, "UTF-8"));
        String s=serverURL + dbPart + "/" + LOOKUP_VIEW + JSON2DB.viewJsonPart + skey;
        System.out.println("request:"+ s);
        result = json2DB.getEntries(json2DB.request2URLString(s), colNames, colTypes);
        if (result==null)return null;
        if (result.size()>0 && result.get(0).get(0).equals(key)){
            System.out.println("key found:"+ key);
            skey=String.format(SEARCH_FROM+MAX_COUNT, URLEncoder.encode(key, "UTF-8"));
            s=serverURL + dbPart + "/" + LOOKUP_VIEW + JSON2DB.viewJsonPart + skey;
            List<List<Object>>res = json2DB.getEntries(json2DB.request2URLString(s), colNames, colTypes);
            result.clear();
            for (List<Object>entry:res) {
                if (entry.get(0).equals(key)) result.add(entry);
            }
        }else if(key.length()>0)return null;
        System.out.println("columns:"+ colNames);
        System.out.println("types:"+ colTypes);
/*
        Map <String,List<List<String>>> map = new HashMap<>();
        map.put(key,result);
        map.put("COLUMNS",Arrays.asList(colNames, colTypes));
*/
        return result;
    }

}
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
плавно переходим к DDS

особенности:
-доступ с правами Editor через веб
1547208842906.png

это когда создаются доки где не заданы авторс (кодом по ссылке так и будет)
-если есть фронт в https - надо обрабатывать редайректы
-либа для http находится /opt/ibm/domino/notes/latest/linux/osgi/rcp/eclipse/plugins/org.apache.commons.httpclient_3.0.0.20180910-1256.jar для домины в линухах
-httpclient_3.0 не умеет в автоматический редайрект и потому нужно использовать . Но тоже уметь приготовить ;)
-авторизация по кукам будет искаропки, но нужно их получить (это описывалось выше)

как использовать редайрект описано // redirect strategy (в коде я привел эту ссылку), но нужно добавить 301 код if(status == 301 || status == 307 || status == 308) {
строка параметров может быть такой
server=<FQDN сервера> database=<путь к базе> resources=views,documents
адаптированный код ниже
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
Java:
package com.setralubs;

import com.ibm.commons.util.io.json.JsonJavaObject;
import com.ibm.commons.util.io.json.JsonObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.*;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Args;

import java.io.IOException;
import java.net.URI;
import java.util.StringTokenizer;

import static com.setralubs.AuthToken.*;
import static org.apache.http.entity.ContentType.*;

/**
 *
 * This is a sample Java application that uses an HTTP client library and a JSON library
 * to perform sample REST style CRUD (Create, Read, Update, and Delete) operations on resources
 * available through the Domino Access Servces API for Data services.
 *
 * The HTTP client library and JSON library used in this sample are available with the installation
 * of the Domino Access Services API on the Domino server.
 *
 * The target database is the XPages Extension Library sample database, xpagesext.nsf, included with
 * the XPages Extension Library download.  See http://extlib.openntf.org/
 *
 * This sample includes:
 *  - GET request and response for DAS resources, e.g., databases, views, view entries.
 *  - Creation of name and password credentials for basic name and password authentication.
 *     - Create, Read, Update and Delete operations for a single document.
 *
 * How to configure and run this sample:
 * (Please see the Domino Access Services documentation for more details on these steps.)
 *
 * Configure the test environment:
 * - Install the Domino Access Services API on the Domino server.
 * - Configure Domino server security to enable access from the DAS API.
 * - Enable "Name and Password" authentication in the TCP Authentication setting for the Domino server.
 * - Add the XPages Extension Library sample database, xpagesext.nsf, to the Domino server data directory.
 * - Use the IBM Lotus Notes client to set the database property for xpagesext.nsf to
 *   allow the "Data" service.
 *
 * Configure the Java development environment:
 * - If you would like to use the HTTP client and JSON libraries available from the DAS install,
 *     add the following jar files to your Java development and runtime environment.
 *     1. [Domino root]\osgi\shared\eclipse\plugins\
 *        com.ibm.commons_8.5.3.yyyymmdd-hhmm\lwpd.commons.jar
 *     2. [Domino root]\osgi\rcp\eclipse\plugins\
 *         org.apache.commons.logging_1.0.4.20110614-1451.jar
 *  3. [Domino root]\osgi\rcp\eclipse\plugins\
 *         org.apache.commons.codec_1.3.0.20110614-1451.jar
 *  4. [Domino root]\osgi\rcp\eclipse\plugins\
 *         org.apache.commons.httpclient_3.0.0.20110614-1451.jar
 *
 * Run the sample as a Java application, with arguments:
 *
 *  Server Address        e.g. server=server.mycompany.com
 *  DatabaseName        e.g. database=xpagesext.nsf
 *  User name (Optional): e.g. user=Myuser/Org
 *  Password  (Optional): e.g. password=mypassword
 *  View name (Optional): e.g. AllContacts
 *  Resources to try (Optional): Comma separated list of one or more of the following:
 *          databases, views, entries, documents
 *              e.g. resources=databases, documents
 *
 */

public class SampleHttpClient {

    public static String userName = AuthToken.userName;
    public static String userPassword = "";
    public static String DominoServerAddress = "";
    public static UsernamePasswordCredentials myCreds = null;
    public static CloseableHttpClient client = null;
    public static String BaseURI = "https://";

    public static final String API_BASE_URI = "/api";
    public static final String API_DATABASES_URI = "/api/data";
    public static final String API_VIEWS_URI = "/api/data/collections";
    public static final String API_DOCUMENTS_URI = "/api/data/documents";

    // argument prefixes
    public static final String SERVER_ARG = "server=";
    public static final String DATABASE_ARG = "database=";
    public static final String USERNAME_ARG = "user=";
    public static final String PASSWORD_ARG = "password=";
    public static final String RESOURCES_ARG = "resources=";
    public static final String VIEWNAME_ARG = "view=";

    // resource arg names
    public static final String RESOURCE_DATABASES = "databases";
    public static final String RESOURCE_VIEWS = "views";
    public static final String RESOURCE_VIEWENTRIES = "entries";
    public static final String RESOURCE_DOCUMENTS = "documents";

    public static String databaseName = dbPart;//"xpagesext.nsf";
    public static String viewName = "All";//"AllNames";
    public static String resourcesArg = "";

    public static void main(String[] args) throws Exception {
        boolean invalidArgs = false;
        JWT jwt = new JWT();
        String encBase64=new String(Base64.encodeBase64(jwt.encrypt(userName, key).getBytes()));
        //https://stackoverflow.com/a/32197667
        RequestConfig customizedRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY).build();
        HttpClientBuilder customizedClientBuilder = HttpClients.custom().setDefaultRequestConfig(customizedRequestConfig);
        //https://stackoverflow.com/a/40982127 redirect strategy
        customizedClientBuilder.setRedirectStrategy(new DefaultRedirectStrategy() {
            public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
                Args.notNull(request, "HTTP request");
                Args.notNull(response, "HTTP response");
                int statusCode = response.getStatusLine().getStatusCode();
                switch(statusCode) {
                    case 301:
                    case 307:
                    case 302:
                    case 308:
                    case 303:
                        return true;
                    case 304:
                    case 305:
                    case 306:
                    default:
                        return false;
                }
            }

            public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException, ProtocolException {
                URI uri = this.getLocationURI(request, response, context);
                String method = request.getRequestLine().getMethod();
                if(method.equalsIgnoreCase("HEAD")) {
                    return new HttpHead(uri);
                } else if(method.equalsIgnoreCase("GET")) {
                    return new HttpGet(uri);
/*
                } else if(method.equalsIgnoreCase("DELETE")) {
                    return new HttpDelete(uri);
                } else if(method.equalsIgnoreCase("PATCH")) {
                    return new HttpPatch(uri);
                } else if(method.equalsIgnoreCase("PUT")) {
                    return new HttpPut(uri);
                } else if(method.equalsIgnoreCase("POST")) {
                    return new HttpPost(uri);
*/
                } else {
                    int status = response.getStatusLine().getStatusCode();
                    HttpUriRequest toReturn = null;
                    if(status == 301 || status == 307 || status == 308) {
                        toReturn = RequestBuilder.copy(request).setUri(uri).build();
                        toReturn.removeHeaders("Content-Length"); //Workaround for an apparent bug in HttpClient
                    } else {
                        toReturn = new HttpGet(uri);
                    }
                    return toReturn;
                }
            }
        });
        // Create the http client
        client = customizedClientBuilder.build();
        //client=HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();
        //set Authorization cookie
        try {
            HttpGet get = new HttpGet(target+encBase64);
            HttpResponse response=client.execute(get);
            printResponseBodyToConsole(response);
        } catch (IOException ioe) {
            System.err.println("Unable to connect to '" + serverURL + "'");
            System.err.println(ioe.getMessage());
            System.exit(-1);
        }
        //System.exit(0);


        if (args.length < 1)
            invalidArgs = true;
        else
        {
            for (int i = 0; i < args.length; i++) {
                String arg = args[i];
                String argsValue = "";

                if (arg.contains(SERVER_ARG)) {
                    argsValue= arg.substring(arg.indexOf(SERVER_ARG) + SERVER_ARG.length());
                    DominoServerAddress = argsValue.trim();
                } else if (arg.contains(DATABASE_ARG)) {
                    argsValue= arg.substring(arg.indexOf(DATABASE_ARG) + DATABASE_ARG.length());
                    databaseName = argsValue.trim();
                } else if (arg.contains(USERNAME_ARG)) {
                    argsValue= arg.substring(arg.indexOf(USERNAME_ARG) + USERNAME_ARG.length());
                    userName = argsValue.trim();
                } else if (arg.contains(PASSWORD_ARG)) {
                    argsValue= arg.substring(arg.indexOf(PASSWORD_ARG) + PASSWORD_ARG.length());
                    userPassword = argsValue.trim();
                } else if (arg.contains(RESOURCES_ARG)) {
                    argsValue= arg.substring(arg.indexOf(RESOURCES_ARG) + RESOURCES_ARG.length());
                    resourcesArg = argsValue.trim();
                } else if (arg.contains(VIEWNAME_ARG)) {
                    argsValue= arg.substring(arg.indexOf(VIEWNAME_ARG) + VIEWNAME_ARG.length());
                    viewName = argsValue.trim();
                }
            }
        }


        if (invalidArgs)
        {
            System.out.println("To run this application specify the following arguments:");
            System.out.println(" Server Address        e.g. server=server.mycompany.com");
            System.out.println(" DatabaseName        e.g. database=xpagesext.nsf");
            System.out.println(" User name (Optional): e.g. user=Myuser/Org");
            System.out.println(" Password  (Optional): e.g. password=mypassword");
            System.out.println(" View name (Optional): e.g. AllContacts");
            System.out.println("\n Resources to try (Optional): Comma separated list of one or more of the following:");
            System.out.println("\t\t " + RESOURCE_DATABASES  + ", " + RESOURCE_VIEWS + ", " + RESOURCE_VIEWENTRIES + ", " + RESOURCE_DOCUMENTS);
            System.out.println("\t\t\t e.g. resources=databases, documents");
            System.out.println("");
            return;
        }

        System.out.println("Running rest test(s) with the following arguments:");
        System.out.println("\tServer Address: " + DominoServerAddress);
        System.out.println("\t" + ((databaseName.length() > 0) ? ("database name = " +databaseName) : "database name was not supplied, using default"));
        System.out.println("\t" + ((viewName.length() > 0) ?  ("view name = " +viewName) : "View name was not supplied, using default"));
        System.out.println("\t" + ((userName.length() > 0) ? ("user name = " +userName) : "User name was not supplied"));
        System.out.println("\t" + ((userPassword.length() > 0) ? "User Password was provided. " : "User password was not supplied"));
        System.out.println("\t" + ((resourcesArg.length() > 0) ? ("Resources to try: " + resourcesArg) : "resources list not specified, default base resource"));
        System.out.println("");

        //HttpClientBuilder.create().
/*
        HttpState state = client.getState();
        HttpParams params = client.getParams();
*/

        // A name and password was supplied, create credentials, otherwise the user is Anonymous
        if (userName.length() > 0 && userPassword.length() > 0) {
            myCreds = new UsernamePasswordCredentials(userName,userPassword);
            System.out.println("Created credentials for " + myCreds.getUserName());
            // Apply the credentials to the httpclient for preemptive authentication.
/*
            params.setAuthenticationPreemptive(true);
            state.setCredentials(AuthScope.ANY, myCreds);
*/
        }

        // Create the base segment of the URI with the target server
        BaseURI = BaseURI + DominoServerAddress;

        if (resourcesArg.length() > 0) {
            // Build the URI and select the test based on arguments from the command line.
            StringTokenizer tokenizer = new StringTokenizer(resourcesArg, ", ");
            while ( tokenizer.hasMoreTokens() ) {
                String resourceName = tokenizer.nextToken();
                if (resourceName.equalsIgnoreCase(RESOURCE_DATABASES)) {
                    testDatabases(BaseURI + API_DATABASES_URI);
                } else if (resourceName.equalsIgnoreCase(RESOURCE_VIEWS)) {
                    testViews(BaseURI + "/" + databaseName + API_VIEWS_URI);
                } else if (resourceName.equalsIgnoreCase(RESOURCE_VIEWENTRIES)) {
                    testViewEntries(BaseURI + "/" + databaseName + API_VIEWS_URI + "/name/" + viewName);
                } else if (resourceName.equalsIgnoreCase(RESOURCE_DOCUMENTS)) {
                    testDocuments(BaseURI + "/" + databaseName +  API_DOCUMENTS_URI);
                }
            }
        }
        else {
            testBase(BaseURI + API_BASE_URI);
        }
    }

    /*
     * Read base URI to DAS Data service
     */
    private static void testBase(String url) {
        try {
            HttpGet get = new HttpGet(url);
            HttpResponse response=client.execute(get);
            printResponseBodyToConsole(response);
        } catch (IOException ioe) {
            System.err.println("Unable to connect to '" + DominoServerAddress + "'");
            System.err.println(ioe.getMessage());
            System.exit(-1);
        }
    }

    /*
     * Get a list of databases
     */
    private static void testDatabases(String url) {
        HttpGet get = null;
        try {
            System.out.println("");
            System.out.println("Test of databases resource..\n");

            get = new HttpGet(url);
            HttpResponse response=client.execute(get);
            printResponseBodyToConsole(response);
            System.out.println("End test of databases resource..\n\n");
        } catch (IOException ioe) {
            System.err.println("Unable to connect to '" + DominoServerAddress + "'");
            System.err.println(ioe.getMessage());
            System.exit(-1);
        }
    }

    /*
     * Get list of views and folders of a database
     */
    private static void testViews(String url) {
        HttpGet get = null;
        try {
            System.out.println("");
            System.out.println("Test of views resource..\n");

            get = new HttpGet(url);
            HttpResponse response=client.execute(get);
            printResponseBodyToConsole(response);
            System.out.println("End test of views resource..\n\n");
        } catch (IOException ioe) {
            System.err.println("Unable to connect to '" + DominoServerAddress + "'");
            System.err.println(ioe.getMessage());
            System.exit(-1);
        }
    }

    /*
     * Get list of entries in a given view
     */
    private static void testViewEntries(String url) {
        HttpGet get = null;
        try {
            System.out.println("");
            System.out.println("Test of view entries resource..\n");

            get = new HttpGet(url);
            HttpResponse  response=client.execute(get);
            printResponseBodyToConsole(response);
            System.out.println("End test of view entries resource..\n\n");
        } catch (IOException ioe) {
            System.err.println("Unable to connect to '" + DominoServerAddress + "'");
            System.err.println(ioe.getMessage());
            System.exit(-1);
        }
    }

    /*
     * Perform REST style CRUD (Create, Read, Update, and Delete) operations on a single document.
     */
    private static void testDocuments(String url) {
        System.out.println("");
        System.out.println("Test of documents resource..\n");

        // Use JSON library methods to create a JSON object representing a new document.
        JsonObject jsonItem = new JsonJavaObject();
        jsonItem.putJsonProperty("FirstName", "Aaron");
        jsonItem.putJsonProperty("LastName", "Adams");
        jsonItem.putJsonProperty("EMail", "aaron_adams@renovations.com");
        jsonItem.putJsonProperty("City", "Quincy");
        jsonItem.putJsonProperty("State", "MA");
        jsonItem.putJsonProperty("Id", "CN=Aaron Adams/O=renovations");
        jsonItem.putJsonProperty("Form", "Contact");
        // Create a new document in the database and return the URI of the document.
        String documentURI = createDocument(url, jsonItem);

        // Read the new document
        HttpResponse  getResponse = readDocument(documentURI);
        if (getResponse.getStatusLine().getStatusCode() == 200) {
            printResponseBodyToConsole(getResponse);
        } else {
            System.out.println("Error: GET return code expected 200, actual "
                    + getResponse.getStatusLine().getStatusCode());
            System.exit(-1);
        }

        // Update the document, change City from "Quincy" to "Braintree".
        jsonItem = new JsonJavaObject();
        jsonItem.putJsonProperty("City", "Braintree");
        updateDocument(documentURI, jsonItem);

        // Read the document after update.
        getResponse = readDocument(documentURI);
        if (getResponse.getStatusLine().getStatusCode() == 200) {
            printResponseBodyToConsole(getResponse);
        } else {
            System.out.println("Error: GET return code expected 200, actual "
                    + getResponse.getStatusLine().getStatusCode());
            System.exit(-1);
        }

        // Delete the document.
        deleteDocument(documentURI);

        // Attempt to read the document after delete, should be not found.
        getResponse = readDocument(documentURI);
        if (getResponse.getStatusLine().getStatusCode() == 404) {
            System.out.println("Document not found, as expected.");
        } else {
            System.out.println("Error: GET return code expected 404, actual "
                    + getResponse.getStatusLine().getStatusCode());
            System.exit(-1);
        }

    }

    /*
     *  Use org.apache.commons.httpclient.methods.PostMethod to create a document.
     *  The new document URI is returned in the Location response-header field.
     */
    private static String createDocument(String url, JsonObject jsonItem) {
        String NewDocURI = null;
        try {
            HttpPost post = new HttpPost(url);
            post.setEntity(new StringEntity(jsonItem.toString()));
            post.addHeader("Content-Type", "application/json");
            post.addHeader("Accept", "application/json");
            HttpResponse response = client.execute(post);
            if (response.getStatusLine().getStatusCode() != 201) {
                System.out.println("Error: Return code " + response.getStatusLine().getStatusCode()
                        + " on POST of url: " + url);
                System.out.println("Please check the test setup, exiting.");
                System.exit(-1);
            }

            Header newLoc = response.getFirstHeader("Location");
            NewDocURI = newLoc.getValue();
            printResponseBodyToConsole(response);
        } catch (IOException ioe) {
            System.err.println("Unable to connect to '" + DominoServerAddress
                    + "'");
            System.err.println(ioe.getMessage());
            System.exit(-1);
        }
        return NewDocURI;
    }

    /*
     * Use org.apache.commons.httpclient.methods.GetMethod to read a document.
     */
    private static HttpResponse readDocument(String url) {
        HttpResponse response=null;
        try {
            HttpGet get = new HttpGet(url);
            get.addHeader("Content-Type", "application/json");
            get.addHeader("Accept", "application/json");
            response=client.execute(get);
        } catch (IOException ioe) {
            System.err.println("Unable to connect to '" + DominoServerAddress
                    + "'");
            System.err.println(ioe.getMessage());
            System.exit(-1);
        }
        return response;
    }

    /*
     * Use org.apache.commons.httpclient.methods.PostMethod with request-header
     * "X-HTTP-Method-Override" set to "PATCH" to update single items on a document.
     *
     * Note the difference of "PATCH" to "PUT" for the DAS API: PATCH allows the replacement of a single
     * item in the document, while PUT will replace the entire document.
     */
    private static void updateDocument(String url, JsonObject jsonItem) {
        try {
            //url=url.replaceAll("http://","https://").replaceFirst(":[0-9]+","");
            HttpPatch put = new HttpPatch(url);
            put.setEntity(
                    new StringEntity(jsonItem.toString(),
                            APPLICATION_JSON));
/*
            put.setHeader("Content-Type", "application/json");
            put.setHeader("Accept", "application/json");
            put.setHeader("X-HTTP-Method-Override", "PATCH");
*/

            HttpResponse response = client.execute(put);
            if (response.getStatusLine().getStatusCode() != 200) {
                System.out.println("Error: Return code " + response.getStatusLine().getStatusCode()
                        + "\nReason:"+response.getStatusLine().getReasonPhrase()
                        + "\n on PUT of url: " + url);
                System.out.println("Please check the test setup, exiting.");
                System.exit(-1);
            }
            System.out.println("success PUT");
            printResponseBodyToConsole(response);
        } catch (IOException ioe) {
            System.err.println("Unable to connect to '" + DominoServerAddress
                    + "'");
            System.err.println(ioe.getMessage());
            System.exit(-1);
        }
    }

    /*
     * Use org.apache.commons.httpclient.methods.DeleteMethod to delete a document.
     */
    private static void deleteDocument(String url) {
        HttpDelete delete = null;
        try {
            //url=url.replaceAll("http://","https://").replaceFirst(":[0-9]+","");
            delete = new HttpDelete(url);
            delete.addHeader("Content-Type", "application/json");
            delete.addHeader("Accept", "application/json");
            HttpResponse response = client.execute(delete);
            printResponseBodyToConsole(response);
            if (response.getStatusLine().getStatusCode() != 200) {
                System.out.println("Error: Return code "
                        + response.getStatusLine().getStatusCode() + " with DELETE on url: "
                        + url);
                System.out.println("Please check the test setup, exiting.");
                System.exit(-1);
            }
        } catch (IOException ioe) {
            System.err.println("Unable to connect to '" + DominoServerAddress
                    + "'");
            System.err.println(ioe.getMessage());
            System.exit(-1);
        }
    }

    /*
     * Print response body to standard out
     */
    private static void printResponseBodyToConsole(HttpResponse response) {
        try {
            System.out.println("Result:"+response.getStatusLine().getReasonPhrase());
            System.out.println(org.apache.http.util.EntityUtils.toString(response.getEntity()));
        } catch (IOException ioe) {
            System.err.println("Unable to connect to '" + DominoServerAddress
                    + "'");
            System.err.println(ioe.getMessage());
            System.exit(-1);
        }
    }

}
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
есть еще момент - работает обновление и создание аттачей (домина Release 9.0.1FP7)
по ссылке на DDS написано что не будет ;), но там для 8.5.3U1
работает как написано здесь
т.е. base64 и тип контента, я сделал так
Java:
    private static void updateDocument(String url, JsonObject jsonItem) {
        try {
            //url=url.replaceAll("http://","https://").replaceFirst(":[0-9]+","");
            HttpPatch put = new HttpPatch(url);
/*
            put.setEntity(
                    new StringEntity(jsonItem.toString(),
                            APPLICATION_JSON));
*/
            String s="{\n" +
                    "\"City\": \"Braintree\",\n"+
                    "  \"Subject\": \"Sample file attachment\",\n" +
                    "  \"Body\": {\n" +
                    "    \"type\": \"multipart\",\n" +
                    "    \"content\": [\n" +
                    "      {\n" +
                    "        \"contentType\": \"image/jpeg; name=\\\"image.jpg\\\"\",\n" +
                    "        \"contentDisposition\": \"attachment; filename=\\\"image.jpg\\\"\",\n" +
                    "        \"contentTransferEncoding\": \"base64\",\n" +
                    "        \"data\": \""+Images.testImage+"\"" +
                    "      }\n" +
                    "    ]\n" +
                    "  }\n" +
                    "}";
            put.setEntity(new StringEntity(s));

            put.addHeader("Content-Type", "application/json");
            put.addHeader("Accept", "application/json");
            //put.addHeader("X-HTTP-Method-Override", "PATCH");

            HttpResponse response = client.execute(put);
            if (response.getStatusLine().getStatusCode() != 200) {
                System.out.println("Error: Return code " + response.getStatusLine().getStatusCode()
                        + "\nReason:"+response.getStatusLine().getReasonPhrase()
                        + "\n on PUT of url: " + url);
                System.out.println("Please check the test setup, exiting.");
                System.exit(-1);
            }
            System.out.println("success PUT");
            printResponseBodyToConsole(response);
            System.out.println("END PUT");
        } catch (IOException ioe) {
            System.err.println("Unable to connect to '" + DominoServerAddress
                    + "'");
            System.err.println(ioe.getMessage());
            System.exit(-1);
        }
    }
где Images.testImage - статик строка созданная из картинки, я создавал base64 image.jpg в бубунте и вставлял через буфер, только надо \n поудалять (при вставке а Идею они добавляются автоматом) результат выгдядит так
1547222390765.png
 
  • Нравится
Реакции: CL1F

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
проверил про права доступа - все норм
т.е. если назначим форму и будем делать computewithform=true - то нет необходимости давать "повышенный" доступ юзерам
строчка при создании дока будет выгдядеть так (форма batch, в ней у меня прописаны авторс): url=url+"?"+"computewithform=true"+"&form=batch";
это до HttpPost post = new HttpPost(url);
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
обратная задача - получение аттача из дока, нужные классы здесь
Java:
import com.ibm.commons.util.io.json.JsonException;
import com.ibm.commons.util.io.json.JsonJavaFactory;
import com.ibm.commons.util.io.json.JsonObject;
import com.ibm.commons.util.io.json.JsonParser;
import org.apache.commons.codec.binary.Base64InputStream;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.LoggerFactory;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

public class AttachTemplate2inDAS extends DASUtilsBase{
......................................................
    public InputStream getIn(String key) throws JsonException {
        InputStream retIs=null;
        try {
            LOG.debug("");
            LOG.debug("Test of view entries resource..\n");

            HttpGet get = new HttpGet(viewURI);
            HttpResponse response=client.execute(get);
            String ret=printResponseBodyToConsole(response);
            LOG.debug("End test of view entries resource..\n\n");
            ObjectMapper mapper = new ObjectMapper();
            JsonNode root=mapper.readTree(ret);
            String href=root.findValue("@link").path("href").asText();
/*
            List<Object> list= (List<Object>) JsonParser.
                    fromJson(JsonJavaFactory.instanceEx,
                            ret);
            String href=((Map<String,Map<String,String>>)list.get(0)).get("@link").get("href");

*/
            response = readDocument(href);
            if (response.getStatusLine().getStatusCode() == 200) {
                ret=printResponseBodyToConsole(response);
                root=mapper.readTree(ret);
                List<String> listData=root.path("body").path("content").findValuesAsText("data");
                //LOG.info(listData.get(listData.size()-1));
                retIs=new Base64InputStream(
                        IOUtils.toInputStream(listData.get(listData.size()-1), "UTF-8"));
                //IOUtils.copy(retIs, new FileOutputStream("add/test/template.docx"));

            } else {
                LOG.debug("Error: GET return code expected 200, actual "
                        + response.getStatusLine().getStatusCode());
                System.exit(-1);
            }
        } catch (IOException ioe) {
            LOG.error("Unable to connect to '" + dominoServer + "'");
            LOG.error(ioe.getMessage());
            System.exit(-1);
        }

        return retIs;
    }
здесь из первого энтриса вьюшки берем УРЛ документа, по нему получаем тело документа и забираем (и декодируем) аттач
используется jackson (для получения из json)
 
Последнее редактирование:

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
получение конфигураций из базы (у меня сделано - опция по имени формы), а интереснее - получени DB RID из линка (если в документе Copy Db link и вставка его в РТ)
Java:
import com.ibm.commons.util.io.json.JsonObject;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class OptionsFromDB extends DASUtilsBase{
    final org.slf4j.Logger LOG = LoggerFactory.getLogger(new Throwable().getStackTrace()[0].getClassName());
    private final String viewURI;
    static final String KEYCOLUMN = "Form";
    private final Map<String, String> map=new HashMap<>();

    public OptionsFromDB() {
        this.viewURI = BaseURI + dominoServer + "/" + getDatabaseName() + API_VIEWS_URI + "/name/" + "Options?";
        HttpResponse response= null;
        HttpGet get = new HttpGet(viewURI);
        try {
            response = client.execute(get);
            String ret= null;
            ret = getResponeAsString(response);
            //ret=printResponseBodyToConsole(response);
            if (response.getStatusLine().getStatusCode()!=200){
                LOG.error("Code: "+response.getStatusLine().getStatusCode()
                        +"\nReason: "
                        +response.getStatusLine().getReasonPhrase()
                        +"\n"+ret
                );
                return;
            }
            ObjectMapper mapper = new ObjectMapper();
            JsonNode root=mapper.readTree(ret);
            root.getElements().forEachRemaining(
                    node ->
                            map.put(node.findValue("Form").asText(), node.findValue("href").asText())
            );

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * get DB RID from configuration doc
     * @param opt key for doc in options view
     * @return
     */
    public String getRID(String opt) throws IOException {
        String ret=getResponeAsString(readDocument(map.get(opt)));
        ObjectMapper mapper = new ObjectMapper();
        JsonNode root=mapper.readTree(ret);
        LOG.debug(ret);
        List<String> list=root.findValuesAsText("data");
        for(int i=list.size()-1;i >= 0;i--){
            if (list.get(i).contains("<a href=")){ret=list.get(i);break;}
        }
        Pattern ptn=Pattern.compile("a?href=.+Notes.+/(.+)\\\"><img(.+)");
        Matcher matcher=ptn.matcher(ret);
        if (matcher.find()){
            return matcher.group(1);
        }
        return null;
    }

    public String getRID(String opt, String name) throws IOException {
        List<String> list=getFieldNode(opt, name).findValuesAsText("data");
        String ret = null;
        for(int i=list.size()-1;i >= 0;i--){
            if (list.get(i).contains("<a href=")){ret=list.get(i);break;}
        }
        Pattern ptn=Pattern.compile("a?href=.+Notes.+/(.+)\\\"><img(.+)");
        Matcher matcher=ptn.matcher(ret);
        if (matcher.find()){
            return matcher.group(1);
        }
        return null;

    }

    public JsonNode getFieldNode(String opt, String name) throws IOException {
        String ret=getResponeAsString(readDocument(map.get(opt)));
        ObjectMapper mapper = new ObjectMapper();
        JsonNode root=mapper.readTree(ret);
        return root.findValue(name);
    }

    public String getFieldString(String opt, String name) throws IOException {
        return getFieldNode(opt, name).asText();
    }

    public static void main(String[]args) throws IOException {
        OptionsFromDB obj=new OptionsFromDB();
        obj.map.entrySet().stream().forEach(e->obj.LOG.debug("option: "+e.getKey()+"; doc ref: "+e.getValue()));
        //search config by form name and fetch RID from field dblink
        obj.LOG.debug(obj.getRID("optCopyDocs","dblink"));
    }

    @Override
    protected JsonObject getDefaultItems() {
        return null;
    }

    @Override
    protected String getForm() {
        return null;
    }
 

VladSh

начинающий
Lotus Team
11.12.2009
1 784
157
BIT
57
Может на гитхабе проект открыть и туда сыпать? А здесь ссылку дать.
Может и люди к разработке подтянутся...
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
Может на гитхабе проект открыть и туда сыпать? А здесь ссылку дать.
Может и люди к разработке подтянутся...
возможно, но на данный момент некогда (надо выковыривать специфику)
 

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 941
609
BIT
214
Нюансы авторизации:
1 - авторизация по имени и паролю с получением кукисов (фактически - LtpaToken)
2 - авторизация по сгенеренному токену

1-ый способ приемлем в однопоточном приложении, а вот для много-поточного использования есть особенности:
- HttpURLConnection (штатны класс в жвм) имеет на борту
Java:
    final static CookieManager cookieManager = new CookieManager();
    static {
        CookieHandler.setDefault(cookieManager);
    }
по коду видно - менеджер кукисов глобальный и его приходится делать статиком (единственная инициализация)
т.е. по истечению срока токена - все "сломается" (т.е всякий запрос будет вываливать страницу авторизации)
- апачевский org.apache.http.* - либа удобная, но есть подозрение - будет тот же исход (т.к. кукисы обрабатываются автоматически, и возможно, глобально, хотя не проверял)
Т.о. вполне логично получать токен на каждый объект взаимодействия по http, и использывать именно его
Java:
    public InputStream request2URL(String target) throws IOException {

        URL url=new URL(target);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (cookies!=null)
            for (String cookie : cookies) {
                conn.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
            }

        InputStream res = null;
        if (conn.getResponseCode() == 200) {
            //System.out.println("OK");
            res= conn.getInputStream();
            if (cookies==null)cookies = conn.getHeaderFields().get("Set-Cookie");
        }else{
            System.out.format("Request status %d -> %s\n",conn.getResponseCode(),conn.getResponseMessage());
        }
        return res;
    }
здесь кукисы были получены из запроса к специальной xPage (код выкладывал) использующей генерацию токена
 
Мы в соцсетях:

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