Показаны сообщения с ярлыком java. Показать все сообщения
Показаны сообщения с ярлыком java. Показать все сообщения

понедельник, 16 августа 2021 г.

Python: последовательное подключение к СУБД Oracle, затем PostgreSQL

 Попытка подключения сначала к СУБД Oracle, а затем к PostgreSQL в таком виде:

import jaydebeapi

...

jaydebeapi.connect('oracle.jdbc.driver.OracleDriver', ora_url, [db_username, ora_password], './ojdbc6.jar')

jaydebeapi.connect('org.postgresql.Driver', pg_url, [pg_user, pg_password], './postgresql-42.2.1.jar')

приводит к ошибке:

TypeError: Class org.postgresql.Driver is not found


Решение: предварительно загрузить JDBC-драйвер СУБД PosgreSQL в экземпляр JVM - см. строку "jpype.startJVM(... classpath=...":

import jaydebeapi

import jpype

...

jHome = jpype.getDefaultJVMPath()

jpype.startJVM(jHome, classpath=['./ojdbc6.jar','./postgresql-42.2.1.jar'])


jaydebeapi.connect('oracle.jdbc.driver.OracleDriver', ora_url, [db_username, ora_password], './ojdbc6.jar')

jaydebeapi.connect('org.postgresql.Driver', pg_url, [pg_user, pg_password], './postgresql-42.2.1.jar')


jpype.shutdownJVM()

суббота, 19 сентября 2020 г.

Решение проблемы с зависанием веб-приложения

Пример анализа и, надеюсь, решения проблемы с зависаниями веб-приложения.

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

Единственной полезной зацепкой была ошибка в "catalina.out" (лог-файл веб-сервера Apache Tomcat 9, при чем не сразу стало понятно, что указанная ниже информация записывается туда, при штатных настройках Apache Tomcat, только после остановки веб-сервера или после остановки проблемного веб-приложения, например, в "Tomcat Manager Application"):
19-Sep-2020 08:26:57.691 WARNING [http-nio-8080-exec-914] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [jenki##2.1.28] is still processing a request that has yet to finish. This is very likely to create a memory leak. You can control the time allowed for requests to finish by using the unloadDelay attribute of the standard Context implementation. Stack trace of request processing thread:[
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
org.apache.tomcat.dbcp.pool2.impl.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:586)
org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:438)
org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:359)
org.apache.tomcat.dbcp.dbcp2.PoolingDataSource.getConnection(PoolingDataSource.java:134)
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:1543)
com.jenki.multicon.AppContextReader.<init>(AppContextReader.java:14)
com.jenki.LoginServlet.doPost(LoginServlet.java:46)
...
Последние две строки дали мне, как автору веб-приложения, понять, что проблема возникла, когда пользователь ввел пароль и началось ожидание подключения к БД для загрузки данных, которые пользователь ожидает на экране своего интернет-браузера. Таким образом, это дало уверенность в том, что на найденную ошибку можно спокойно опереться при дальнейшем анализе.

Поиск по остальным строкам стека ошибки привел к подобного рода обсуждениям: https://github.com/dotCMS/core/issues/7790 - тут описываются нюансы настройки подключений к БД через "context.xml" Томката (как раз, мой случай) с использованием параметров:
maxActive="60" maxIdle="10" maxWait="60000" removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true" validationQuery="SELECT 1" testOnBorrow="true"
После попытки применения указанных на странице по ссылке параметров "maxActive", "maxWait" Томкат при запуске в своей консоли сообщает о том, что эти параметры для "фабрики пула соединений" устарели и вместо них нужно использовать актуальные, соответственно, "maxTotal" (по умолчанию "8" - Привет, зависания после 8 обновлений веб-страницы!), "maxWaitMillis" (по умолчанию "-1"). Там же Томкат сообщает наименование текущей фабрики подключений - "org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory" - оказывается, эта фабрика запускается Томкатом 9 автоматически, если администратор в context.xml в блоке настроек для подключения к БД не указывает другую фабрику с помощью тэга "factory" (описано в https://tomcat.apache.org/tomcat-9.0-doc/config/context.html#Resource_Definitions).

Поиск дополнительной информации на тему зависаний веб-приложения после 8 подключений к БД приводит к совету https://stackoverflow.com/questions/30879706/why-does-my-tomcat-only-open-8-jdbc-connections об использовании «factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"».

В итоге, блок настройки подключений к БД веб-приложения выглядит следующим образом:
    <Resource name="jdbc/jenki"
        auth="Container"
        driverClassName="oracle.jdbc.driver.OracleDriver"
        url="jdbc:oracle:thin:@myserver:1521:db"
        username="mySYSDBA"
        password="mypassw"
        type="javax.sql.DataSource"
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
        maxActive="100" maxIdle="30" maxWait="10000"
        removeAbandoned="true" removeAbandonedTimeout="40" logAbandoned="true" testOnBorrow="true" />

Теперь в логе Томката (catalina.out) видны лишь строки, символизирующие закрытие подключений (позднее будет проведена проверка кода приложения - возможно, подключения не всегда корректно закрываются, но пока с этим справляется "Tomcat JDBC Pool Cleaner"):
23-Sep-2020 12:27:26.355 WARNING [Tomcat JDBC Pool Cleaner[2129789493:1600853171352]] org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[oracle.jdbc.driver.T4CConnection@3af0c98d]:java.lang.Exception
...
23-Sep-2020 12:52:51.415 WARNING [Tomcat JDBC Pool Cleaner[2129789493:1600853171352]] org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[oracle.jdbc.driver.T4CConnection@6ea26def]:java.lang.Exception
...
23-Sep-2020 14:02:51.570 WARNING [Tomcat JDBC Pool Cleaner[2129789493:1600853171352]] org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[oracle.jdbc.driver.T4CConnection@41e58b1f]:java.lang.Exception
...
23-Sep-2020 14:04:26.574 WARNING [Tomcat JDBC Pool Cleaner[2129789493:1600853171352]] org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[oracle.jdbc.driver.T4CConnection@338e76fa]:java.lang.Exception
...
23-Sep-2020 14:52:16.686 WARNING [Tomcat JDBC Pool Cleaner[2129789493:1600853171352]] org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[oracle.jdbc.driver.T4CConnection@2165cd9c]:java.lang.Exception
===========================
Порядок действий для стабильного повторения:
1. Открываем несколько разных сессий к веб-приложению (можно даже под одним и тем же пользователем, главное, чтобы это были разные сессии), для этого нужно, к примеру, если тестируется на одном компьютере, то можно открыть 6 окон в 3-х разных браузерах (к примеру, Яндекс.Браузер, Firefox, Chrome): 3 окна в штатном режиме и 3 окна в приватном;
2. Несколько раз (около 6 в каждом окне по очереди) обновляем страницу;
3. Ждем около 20-30 минут (окна браузеров не закрываем);
4. Повторяем пункт 2.

Ожидаемый результат (до исправления):
обновление страницы будет выполнено штатно, пользователь увидит данные на обновленной странице.

Фактический результат (до исправления):
Примерно 4 из 6 окон перейдут в режим ожидания ответа от веб-сервера.

Результат тестирования после примененного исправления ...

среда, 16 сентября 2020 г.

Зависание сервлета

Почему-то при наличии строки
String defaultServer = new AppDatabaseConnectionObject().getDefaultServer();
в классе "DataviewerServlet" веб-страница "зависает" после 8-го обновления страницы в браузере.

Причина мне пока не понятна.
AppDatabaseConnectionObject.java:
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class AppDatabaseConnectionObject {
    private Connection connection;
    private String defaultServer;

    public AppDatabaseConnectionObject(
    ) throws ClassNotFoundException, NamingException, SQLException {
        Context context = new InitialContext();
        DataSource datasource = (DataSource) context.lookup("java:/comp/env/jdbc/myapp");
        connection = datasource.getConnection();
        defaultServer = (String) context.lookup("java:/comp/env/myapp/defaultServer");
    }

    public Connection getConnection() {
        return connection;
    }

    public String getDefaultServer() {
        return defaultServer;
    }
}
DataviewerServlet.java:
import ch.qos.logback.classic.Logger;
import com.myapp.AppDatabaseConnectionObject;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class DataviewerServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            Connection con = new AppDatabaseConnectionObject().getConnection();
            String defaultServer = new AppDatabaseConnectionObject().getDefaultServer();
...

Исправил, заменив в классе "DataviewerServlet" эти строки:
Connection con = new AppDatabaseConnectionObject().getConnection();
String defaultServer = new AppDatabaseConnectionObject().getDefaultServer();
на эти:
AppDatabaseConnectionObject appdbcon = new AppDatabaseConnectionObject();
Connection con = appdbcon.getConnection();
String defaultServer = appdbcon.getDefaultServer();

вторник, 15 сентября 2020 г.

Хранение переменных в context.xml

Почему-то не смог применить пример с хранением переменной в "context.xml" в теге "Parameter" (попытка обращения завершается ошибкой "javax.naming.NameNotFoundException: Name [companyName] is not bound in this Context. Unable to find [companyName]"), зато помог тег "Environment":
<Environment name="companyName" value="My Company, Incorporated" type="java.lang.String" override="false"/>

Оба примера показаны здесь.

суббота, 11 июля 2020 г.

Потокобезопасность. Начало.

Мое знакомство с многопоточностью.

Плохой пример:
public class PingServlet extends HttpServlet {
    private List OutputList = new ArrayList<>();
    private List OutputErrorList = new ArrayList<>();
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        OutputList.clear();
        OutputErrorList.clear();
        try {
            String ip = request.getParameter("ip");
            InetAddress host = InetAddress.getByName(ip);
            int ping_count = 4;
            int ping_timeout_seconds = 2;
            int ping_timeout_milliseconds = ping_timeout_seconds * 1000;
            int ping_ttl = 54;
            OutputList.add("Обмен " + ping_count + " пакетами с timeout " + ping_timeout_seconds + " сек. и TTL " + ping_ttl + ".");
            int i = 1;
            while (i <= ping_count) {                 if (host.isReachable(null, ping_ttl, ping_timeout_milliseconds)) {                     OutputList.add(ip + ": ОК.");                 } else {                     OutputList.add(ip + ": узел недоступен.");                 }                 i++;             }         } catch (Exception e) {             e.printStackTrace();             OutputErrorList.add(e.toString());         }         response.setContentType("text/html; charset=UTF-8"); // Для правильной обработки кириллицы.         if (request.getCharacterEncoding() == null) { // Без этого неправильно выполнялась обработка ввода с кирилицей.             request.setCharacterEncoding("UTF-8");         }         request.getSession().setAttribute("servlet_data_ping", OutputList);         request.getSession().setAttribute("servlet_error_ping", OutputErrorList);         request.getRequestDispatcher("ping.jsp").include(request, response);     } }

Внимание на эти строки:



При такой реализации одновременное выполнение в нескольких потоках приводит к смешиванию значений из нескольких потоков в одной переменной:


Один из вариантов исправления:
public class PingServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List OutputList = new ArrayList<>();
        List OutputErrorList = new ArrayList<>();
        try {
            String ip = request.getParameter("ip");
            InetAddress host = InetAddress.getByName(ip);
            int ping_count = 4;
            int ping_timeout_seconds = 2;
            int ping_timeout_milliseconds = ping_timeout_seconds * 1000;
            int ping_ttl = 54;
            OutputList.add("Обмен " + ping_count + " пакетами с timeout " + ping_timeout_seconds + " сек. и TTL " + ping_ttl + ".");
            int i = 1;
            while (i <= ping_count) {                 if (host.isReachable(null, ping_ttl, ping_timeout_milliseconds)) {                     OutputList.add(ip + ": ОК.");                 } else {                     OutputList.add(ip + ": узел недоступен.");                 }                 i++;             }         } catch (Exception e) {             e.printStackTrace();             OutputErrorList.add(e.toString());         }         response.setContentType("text/html; charset=UTF-8"); // Для правильной обработки кириллицы.         if (request.getCharacterEncoding() == null) { // Без этого неправильно выполнялась обработка ввода с кирилицей.             request.setCharacterEncoding("UTF-8");         }         request.getSession().setAttribute("servlet_data_ping", OutputList);         request.getSession().setAttribute("servlet_error_ping", OutputErrorList);         request.getRequestDispatcher("ping.jsp").include(request, response);     }     protected void doPost(HttpServletRequest request, HttpServletResponse response) {     } }


Внимание на эти строки:

четверг, 14 мая 2020 г.

Доступ к СУБД Firebird 3.0 через JSP под Tomcat

Пример доступа к БД Firebird 3.5 через JSP под Tomcat.

Чтобы научить Apache Tomcat 9 под Java 1.8 подключаться к базам Firebird 3.0, копируем из архива jaybird-4.0.0.java8.zip файлы jaybird-full-4.0.0.java8.jar, lib\antlr-runtime-4.7.2.jar, lib\connector-api-1.5.jar, lib\jna-5.5.0.jar в папку <tomcat>\lib.
Создаем web-приложение: JSP-страница, которая будет выводить содержимое таблицы "USER" из БД "c:/data/base.fdb" сервера "dbserver"
<tomcat>\webapps\test_app\index.jsp

Листинг index.jsp:
<%@page import="java.sql.*" %>
<%Class.forName("org.firebirdsql.jdbc.FBDriver"); %>
<HTML>
    <HEAD>
        <TITLE>Database access through JSP</TITLE>
    </HEAD>
    <BODY>
        <H1>Result of select query</H1>
        <%
            Connection connection = DriverManager.getConnection(
                "jdbc:firebirdsql:dbserver/3255:c:/data/base.fdb",
                "SYSDBA",
                "masterkey");
            Statement statement = connection.createStatement();
            ResultSet resultset = statement.executeQuery("select id, name from user order by id asc");
        %>
        <TABLE BORDER="1">
            <TR>
                <TH>id</TH>
                <TH>name</TH>
            </TR>
            <% while(resultset.next()){ %>
            <TR>
                <TD> <%= resultset.getString(1) %></TD>
                <TD> <%= resultset.getString(2) %></TD>
            </TR>
            <% } %>
        </TABLE>
    </BODY>
</HTML>

четверг, 16 мая 2019 г.

Пример LDAP на Java

1. Узнаем адрес DC-сервера. Для этого на компьютере, включенном в домен, выполняем команду "systeminfo" и из ее результата запоминаем значения параметров "Домен" и "Сервер входа в сеть". Например:
«...
Домен: mydomain.my
Сервер входа в сеть: \\dc-server

...».
1.1. Получаем имя актуального сервера домена с помощью команды:
«...
nslookup mydomain.my
dc-server

...».

2. Создаем пример класса, с учетом справочной информации "LDAP Authentication", "LDAP & LDAPS URLs", либо берем готовый пример - "LoginLDAP.java" на stackoverflow и компилируем.

3. Запускаем класс из п.2 с учетом информации из п.1.1:
java -cp . test.LoginLDAP url=ldap://dc-server:389 username=myusername@mydomain.my password=mypassword
При успешной авторизации, результатом команды будет нечто подобное:
«
distinguishedName: CN=Иванов Иван Иванович,OU=Подразделение,OU=Филиал,OU=Компания,OU=Организация,DC=mydomain,DC=my
memberOf: CN=...
memberOf: CN=...

».
При неудачной попытке, будет сообщение об ошибке, пример, для некорректного пароля:
«
Exception in thread "main" javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C09042F, comment: AcceptSecurityContext error, data 52e, v2580 ]
...».
P.S. Запускать пример можно уже с компьютера, который в домен не включен. Работоспособный вариант для WinDC (для других LPAD-серверов не проверялось). Не проверялась работоспособность LDAPS, только LDAP.

среда, 12 сентября 2018 г.

Java: гадание по стеку ошибки

Пример стека ошибки:
java.text.ParseException: Unparseable date: ""
    at java.text.DateFormat.parse(DateFormat.java:366) ~[na:1.8.0_45]
    at com.bssys.shared.BankUpdateED807Launcher.processRecord(BankUpdateED807Launcher.java:352) [AzkServer.jar:na]
    at com.bssys.shared.BankUpdateED807Launcher.processSingleFile(BankUpdateED807Launcher.java:265) [AzkServer.jar:na]
    at com.bssys.shared.BankUpdateED807Launcher.process(BankUpdateED807Launcher.java:116) [AzkServer.jar:na]
    at com.bssys.shared.BankUpdateED807Launcher.run(BankUpdateED807Launcher.java:95) [AzkServer.jar:na]
    at com.bssys.server.schedule.GenericSchTaskProcessor$1.process(GenericSchTaskProcessor.java:50) [Server.jar:na]
    at com.bssys.server.processor.AbstractProcessor.process(AbstractProcessor.java:90) [Server.jar:na]
    at com.bssys.server.system.XMLProcessor.processElementRes(XMLProcessor.java:123) [Server.jar:na]
    at com.bssys.server.system.TransactJob.process(TransactJob.java:386) [Server.jar:na]
    at com.bssys.server.system.TransactJob.run(TransactJob.java:293) [Server.jar:na]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]

Пример нахождения проблемной строки в байткоде на примере "luyten" (в меню "Settings" включить режим "Bytecode" и галочку "Show Line Numbers Bytecode"):

Примечание: для данного стека ошибки не удалось найти отражение нужной строки байткода (строки № 352) в режиме просмотра "Java", но и в режиме "Bytcode" информации оказалось достаточно.


Иногда проблемную строку байткода можно увидеть в режиме "Java", вот пример стека ошибки:
java.lang.NullPointerException: null
    at com.bssys.azkserver.sofit.common.expimp.export_fk.doc.zr.ExportZR195.getKbkRcp(ExportZR195.java:162) ~[AzkSofit.jar:na]
    at com.bssys.azkserver.sofit.common.expimp.export_fk.doc.zr.ExportZR195.getZRST(ExportZR195.java:118) ~[AzkSofit.jar:na]

Вот проблемная строка в байткоде в режиме "Java":


Та же проблемная строка в байткоде в режиме "Bytecode":

четверг, 10 мая 2018 г.

Java: получение имени хоста по IP-адресу

Пример:
package com.myjava.ip;
 
import java.net.InetAddress;
import java.net.UnknownHostException;
 
public class MyHostName {
 
    public static void main(String args[]){
     
        try {
            InetAddress host = InetAddress.getByName("72.167.232.155");
            System.out.println(host.getHostName());
        } catch (UnknownHostException ex) {
            ex.printStackTrace();
        }
    }
}

Если имя хоста найдено, тогда возвращает имя хоста.
Если имя хоста не найдено, тогда возвращает IP-адрес.
Если IP-адрес некорректный, тогда возвращает java.net.UnknownHostException.

Отсюда.

вторник, 6 марта 2018 г.

Пример Hello World + JSP + Java-classes

WEB-INF/classes/com/example/HelloWorld.java:
package com.example;

public class HelloWorld
{
  public static String hello;
// setter-method:
  public static void setHello(String newhello) {
    hello = newhello;
  }
// getter-method:
  public static String getHello() {
    return hello;
  }
}

index.jsp:
<%@ page import="com.example.HelloWorld"%>

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Servlet example</title>
  </head>
  <body>
    <%
    HelloWorld.setHello("Hello World 2");
    out.println(HelloWorld.getHello());
    %>
  </body>
</html>

Пример сервлета

На деле так никто, конечно, делать не будет, но в качестве примера пойдет:

index.jsp:
<%@ page import="java.sql.Connection"%>
<%@ page import="java.sql.DriverManager"%>
<%@ page import="java.sql.DatabaseMetaData"%>
<%@ page import="java.sql.ResultSet"%>
<%@ page import="java.sql.SQLException"%>
<%@ page import="java.sql.Statement"%>
<%@ page import="java.util.Properties"%>
<%@ page import="java.io.FileInputStream"%>
<%@ page import="java.io.File"%>
<%@ page import="java.io.IOException"%>

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Servlet example</title>
  </head>
  <body>
    <b><%
    int count;
    Properties props = new Properties();
    props.load(new FileInputStream(new File(application.getRealPath("WEB-INF/classes/myapp.properties"))));
    String dbUrl = props.getProperty("myapp.db.url");
    String dbUser = props.getProperty("myapp.db.user");
    String dbPass = props.getProperty("myapp.db.password");
    String[] splt = dbUrl.split(":",3);
    String dbType = splt[1].toUpperCase();
    String query = "select count(*) from sysuser";
    Properties conProps = new Properties();
    conProps.put("user", dbUser);
    conProps.put("password", dbPass);
    conProps.put("charSet", "Cp1251");
    Connection con = DriverManager.getConnection(dbUrl, conProps);
    DatabaseMetaData meta = con.getMetaData();
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery(query);
    while (rs.next()) {
      count = rs.getInt(1);
      out.println("Count of users = " + count);
      out.println("<br>dbType=" + dbType);
    }
    %></b>
  </body>
</html>

Вывод даты-времени на JSTL и Java

Java:
<%@ page import="java.util.Date"%>
<%@ page import="java.text.SimpleDateFormat"%>
<%
SimpleDateFormat fmt = new SimpleDateFormat("dd.MM.yyyy HH:mm");
date = new Date();
out.println(fmt.format(date));
%>

Java (то же самое, только без переменных):
<%@ page import="java.util.Date"%>
<%@ page import="java.text.SimpleDateFormat"%>
<%out.println(new SimpleDateFormat("dd.MM.yyyy HH:mm").format(new Date()));%>
JSTL:
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<fmt:formatDate type="both" pattern="dd.MM.yyyy HH:mm" value="<%=new java.util.Date()%>"/>

понедельник, 5 марта 2018 г.

Import class in JSP

index.jsp:
<%@ page import="MyPackage.MyClass" %>
...
MyClass.class file location:
<tomcat>\webapps\<MyWebApp>\WEB-INF\classes\MyPackage\MyClass.class

MyClass.java:
package MyPackage;
...
import com.example.MyAnotherClass;

MyAnotherClass.class file location:
<tomcat>\webapps\<MyWebApp>\WEB-INF\classes\com\example\MyAnotherClass.class

воскресенье, 4 марта 2018 г.

Пример считывания ini-файла в Java

Example1.java:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.File;
import java.util.Properties;

public class Example1
{
  private static String dbUrl;

  public Example1() throws IOException
  {
    Properties props = new Properties();
    props.load(new FileInputStream(new File("./myfile.properties")));
    dbUrl = props.getProperty("db.url");
    System.out.println(dbUrl);
  }

  public static void main(String[] args) throws IOException
  {
    new Example1();
  }
}

javac Example1.java
java -cp . Example1

вторник, 27 февраля 2018 г.

Java + SQL = JDBC

Select1.java:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Select1 {

    private static final String url = "jdbc:oracle:thin:@172.21.10.56:1521:ora";
    private static final String user = "AZ_USER";
    private static final String password = "AZ_PSWD";

    private static Connection con;
    private static Statement stmt;
    private static ResultSet rs;

    public static void main(String args[]) {
        String query = "select count(*) from sysuser";
        try {
            con = DriverManager.getConnection(url, user, password);
            stmt = con.createStatement();
            rs = stmt.executeQuery(query);

            while (rs.next()) {
                int count = rs.getInt(1);
                System.out.println("Total number of users: " + count + ".");
            }

        } catch (SQLException sqlEx) {
            sqlEx.printStackTrace();
        } finally {
            try { con.close(); } catch(SQLException se) { /*can't do anything */ }
            try { stmt.close(); } catch(SQLException se) { /*can't do anything */ }
            try { rs.close(); } catch(SQLException se) { /*can't do anything */ }
        }
    }
}

Компиляция:
javac Select1.java
Если поместить "ojdbc6.jar" в папку .\lib\ тогда команда запуска будет выглядеть так:
java -cp .;.\lib\ojdbc6.jar Select1
или так:
java -cp .;.\lib\* Select1

понедельник, 26 февраля 2018 г.

Groovy-скрипты для АЦК. Примеры.

Само выражение groovy-скрипта дожно быть условием (при этом указывать "if" необязательно, см.примеры ниже, сам groovy-скрипт всегда возвращает только 2 значения: "true" или "false" (по-умолчанию "false"), соответственно, пункт "Подписать" либо будет показан пользователю, либо - нет):
Примеры:
1) покажет пункт "Подписать" только если пользователь открывает меню действий документа класса 197:
document.documentclass_id.value == 197L;
2) покажет пункт "Подписать" только если пользователь открывает меню действий документа классов, у которых есть поле "CONTRACTOR_ID" (например, 3, 210, 197) и это поле содержит значение "302000014441":
document.contractor_id.value == 302000014441L;
Примечание: после слова "document" можно указывать те реквизиты, что упомянуты в классе, на который ссылается "Имя серверного класса обработчика документа".

Обратная связь:
Можно проверять значения реквизитов объектов, например, скрипт "println document.documentclass_id.value" будет выводить в окно консоли СП номер класса документа, который запустил скрипт.

Можно писать целые блоки:
import java.sql.*;
// Получаем ID органиации, которая указана в поле "Принадлежность к организации" текущего пользователя:
final PreparedStatement pstmt = con.prepareStatement("select u.org_id from usersession s join sysuser u on u.id=s.sysuser_id where s.id=?");
pstmt.setLong(1, con.session.getId());
//Можно применять запрос без параметров (см.конец следующей строки):
//final PreparedStatement pstmt = con.prepareStatement("select u.org_id from usersession s join sysuser u on u.id=s.sysuser_id where s.id=" + con.session.getId());
final ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
println rs.getString("org_id");
}
//Без этой строки в потоке вывода будет появляться предупреждение: "Some statements were not closed":
pstmt.close();

Еще пример:
import java.sql.*;
// Получаем ID организации из поля "Принадлежность к организации" текущего пользователя
Long usrOrgId = 0;
final PreparedStatement pstmt_usr = con.prepareStatement("select u.org_id from usersession s join sysuser u on u.id=s.sysuser_id where s.id=?");
pstmt_usr.setLong(1, con.session.getId());
final ResultSet rs_usr = pstmt_usr.executeQuery();
while (rs_usr.next()) {
usrOrgId = rs_usr.getLong("org_id");
}
pstmt_usr.close();
// Получаем ID бюджетополучателя текущего документа
Long docRecId = 0;
final PreparedStatement pstmt_doc = con.prepareStatement("select recipient_id from conbudget where contract_id=?");
pstmt_doc.setLong(1, document.id.value);
final ResultSet rs_doc = pstmt_doc.executeQuery();
while (rs_doc.next()) {
docRecId = rs_doc.getLong("recipient_id");
}
pstmt_doc.close();
//Сравниваем:
usrOrgId == docRecId;

В логе АЦК:

В логе СП АЦК информация о документе, связанном с ним groovy-скрипте, и результате выполнения этого скрипта выводится, начиная с уровня журнализации "DEBUG", в следующем виде (данные о документе отражаются после слова "document:", содержимое скрипта - после слова "script:", результат выполнения скрипта - после слова "result:", результатом выполнения скрипта могут быть три значения: "false", "null", "true" (примечание: если в правиле указан скрипт, тогда действие "Подписать" появляется у документа только при этом значении)), см. пример:

22.07.22 12:28:26.899,ORB-726433(535),DEBUG,GroovyExecutor,Script completed for:
document: EXPASSIGNMENT: ID=2400000129811;VERSION=3;DOCUMENT_ID=2400005674113;DOCUMENTCLASS_ID=128;DISPSTATUS_ID=0;...
script: return false;
result: false

вторник, 16 мая 2017 г.

(решено) Сбой "Oracle SQL Developer" после запуска дополнительной видеокарты (Windows)

После установки дополнительной видеокарты для работы с двумя мониторами одновременно IDE "Oracle SQL Developer" стал аварийно завершать работу через произвольный промежуток времени после запуска.
Это позволило мне узнать, что:
- отчеты о сбое "Hot Spot" ВМ Java хранятся здесь: <сборка Orale SQL Developer>\sqldeveloper\bin\hs_err_<PID>.log
- настройки IDE хранятся здесь: <сборка Orale SQL Developer>\sqldeveloper\bin\sqldeveloper.conf

Рекомендации по сбою нашел здесь:
http://stackoverflow.com/questions/40651162/sql-developer-crashes-randomly-every-time:

The crash has happened inside atiglpxx.dll, which seems to be a part of graphics driver.
Try one or more of the following options:
1) Add -Dsun.awt.nopixfmt=true JVM argument;
2) Remove -Dsun.java2d.noddraw=true and -Dsun.java2d.ddoffscreen=false arguments;
3) Install different graphics driver.

Помогли рекомендации из пп. 1 и 2.

Архив