четверг, августа 19, 2010

Визуальное представление алгоритмов сортировки

Lady Java

суббота, августа 07, 2010

Ubuntu Tweak

Я вот с Линухом не очень часто тружусь, поэтому кое-что постоянно забывается.
Прочитал про Ubuntu Tweak, удобная штука для таких, как я.

Ubuntu Tweak is an application to config Ubuntu easier for everyone.
It provides many useful desktop and system options that the default desktop environment doesn't provide.

понедельник, июля 26, 2010

Как получить курсор из хранимой процедуры Oracle - SimpleJdbcCall

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

Итак, есть такая табличка - разумеется, что здесь всё упрощено насколько это можно - и даже чуть более

CREATE TABLE BOOK (
    ID INTEGER NOT NULL PRIMARY KEY, 
    NAME VARCHAR2(20))

Есть такая вот хранимая процедура

PROCEDURE GET_BOOKS_BY_NAME (book_cursor OUT SYS_REFCURSOR, name_template IN VARCHAR2)
IS
BEGIN
  OPEN book_cursor FOR
    SELECT b.ID as ID, b.NAME as NAME 
      FROM BOOK b
     WHERE b.NAME LIKE name_template
     ORDER BY ID;    
  
END GET_BOOKS_BY_NAME;

Осталась самая малость - получить от этой процедуры содержимое курсора book_cursor.

Для начала, понадобится получить экземпляр SimpleJdbcCall. Его можно создать руками, можно прописать в контексте спринга - по вкусу.

Для представления данных удобно создать отдельный DTO


public class BookItem {
    private Integer id;
    private String name;
    public BookItem() {}
    // getters и setters опущены 
}


На экземпляры этого класса будут отображены данные из получаемого курсора.

А теперь собираем всё вместе и получаем данные


    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("app-config.xml");


        SimpleJdbcCall simpleJdbcCall = context.getBean("simpleJdbcCall", SimpleJdbcCall.class);


        // Этот экземпляр отвечает за отображение набора данных, полученных из
        // базы данных в курсоре, на список объектов
        RowMapper rowMapper = ParameterizedBeanPropertyRowMapper.newInstance(BookItem.class);
        // Указывается имя вызываемой хранимой процедуры
        simpleJdbcCall.withProcedureName("GET_BOOKS_BY_NAME");
        // Связывается курсор, получаемый из хранимой процедуры, с отображателем
        // данных
        simpleJdbcCall.returningResultSet("BOOK_CURSOR", rowMapper);


        // Задаются входные параметры для хранимой процедуры
        SqlParameterSource params = new MapSqlParameterSource().addValue("NAME_TEMPLATE", "NEW%");


        // Теперь производится непосредственный вызов хранимой процедуры.
        // В возвращаемый в результате вызова map помещается имя курсора
        // (параметр типа String) и сами полученные данные в виде ArrayList.
        // Для того, чтобы эти данные из ArrayList разобрать, и используется
        // rowMapper
        Map resultMap = simpleJdbcCall.execute(params);


        // При этом вызове производится отображение полученных данных на тип,
        // указанный в параметре rowMapper
        @SuppressWarnings("unchecked")
        List resultList = (List) resultMap.get("BOOK_CURSOR");


        // А теперь просто работаем с тем, что получили от БД
        System.out.println("Получено записей: " + resultList.size());
        for (BookItem item : resultList) {
            System.out.println(item);
        }
    }

Вот и всё.

вторник, июля 06, 2010

Glassfish, Spring, и RAR5031:System Exception

Приложение имеет следующий простой вид: EJB SLSB фасад, который обращается с контексту Спринга, получает из него реализацию сервиса и делегирует вызов этом полученному сервису.

В ряде совершенно вроде бы безобидных случаев вываливался exception, начинающийся вот так:

RAR5031:System Exception.
java.lang.NullPointerException
at com.sun.enterprise.resource.ConnectorXAResource.getResourceHandle(ConnectorXAResource.java:228)
at com.sun.enterprise.resource.ConnectorXAResource.start(ConnectorXAResource.java:124)
at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.enlistResource(J2EETransactionManagerOpt.java:159)
at com.sun.enterprise.resource.ResourceManagerImpl.registerResource(ResourceManagerImpl.java:144)
at com.sun.enterprise.resource.ResourceManagerImpl.enlistResource(ResourceManagerImpl.java:102)
at com.sun.enterprise.resource.PoolManagerImpl.getResource(PoolManagerImpl.java:216)
at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:327)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:189)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:158)
at com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:108)
at org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider.getConnection

Случаи были совсем безобидные - вида (автоматического, разумеется) обращения к БД для генерации идентификатора (через TableGenerator) или в случае вызова тразакционного спрингового компонента из транзакционного же EJB SLSB... Короче, во всех этих случаях ничего ломаться бы и не должно было - но ломалось.

Стэктрейс в этой ситуации был реально большим, вот здесь я оставил из него только классы исключений, убрав имена и адреса методов

RAR5031:System Exception.
java.lang.NullPointerException

RAR5031:System Exception.
com.sun.enterprise.resource.PoolingException: java.lang.NullPointerException
RAR5029:Unexpected exception while registering component.
java.lang.RuntimeException: Got exception during XAResource.start:
poolmgr.err_enlisting_res_in_getconn
RAR5117 : Failed to obtain/create connection from connection pool [ ]. Reason : java.lang.RuntimeException: Got exception during XAResource.start:
RAR5114 : Error allocating connection : [Error in allocating a connection. Cause: java.lang.RuntimeException: Got exception during XAResource.start:]

--In J2EETransaction.rollback, jtsTx=null nonXAResource=null
ejbDestroyed: BookServiceBean; id: [B@159b1a0
--In J2EETransaction.rollback, jtsTx=null nonXAResource=75
context with empty container in ContainerSynchronization.afterCompletion
EJB5018: An exception was thrown during an ejb invocation on [BookServiceBean]

javax.ejb.EJBException
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection
Caused by: org.hibernate.exception.GenericJDBCException: Cannot open connection
Caused by: java.sql.SQLException: Error in allocating a connection. Cause: java.lang.RuntimeException: Got exception during XAResource.start:
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection
Caused by: org.hibernate.exception.GenericJDBCException: Cannot open connection
Caused by: java.sql.SQLException: Error in allocating a connection. Cause: java.lang.RuntimeException: Got exception during XAResource.start:
Caused by: java.rmi.RemoteException: null; nested exception is:
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection
Caused by: org.hibernate.exception.GenericJDBCException: Cannot open connection
Caused by: java.sql.SQLException: Error in allocating a connection. Cause: java.lang.RuntimeException: Got exception during XAResource.start:
javax.ejb.EJBException: nested exception is: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.RemoteException: null; nested exception is:
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection

Проблема оказалась в следующем: не было установлено свойство allow-non-component-callers в описании пула соединений. После того, как свойство это установил - все проблемы кончились.

К слову, документация по этому поводу сообщает:
You can allow non-Java-EE components, such as servlet filters and third party persistence managers, to use this JDBC connection pool. The returned connection is automatically enlisted with the transaction context obtained from the transaction manager. Standard Java EE components can also use such pools. Connections obtained by non-component callers are not automatically closed at the end of a transaction by the container. They must be explicitly closed by the caller.

суббота, мая 08, 2010

Извращённые способы перевода

Я не понимаю, как наши переводчики умудряются так работать.

В переводе "Grails in Action" получил название "Grails. Гибкость Groovy и надежность Java".
Вместо того, чтобы по возможности максимально подчеркнуть тот факт, что основа для перевода относится к уважаемой manning-овской серии ... In Action и обозвать как-нибудь "Grails в действии" - замутили что-то непонятное, непотребное.

четверг, мая 06, 2010

Mindmapping - обзор, советы и инструменты

Обзор разных тулзов для делания mindmapping-диаграмм, советы по организации, построению, использованию и другим прочим полезным вещам.
Bulletproof of Mind Mapping: Overview, Benefits, Tips and Tools

вторник, апреля 20, 2010

Apache Commons Lang - ToStringBuilder, формирование строки и форматы

Для определённости, возьём такой простой класс:

class Book {
    private String title;
    private String author;
    private Double price;
    private Date   publDate; 
    ... 
}


Я хочу для этого класса получить toString-like отображение.
Удобный для этого способ - взять и применить ToStringBuilder из библиотеки apache commons lang.

Полное имя этого класса -  org.apache.commons.lang.builder.ToStringBuilder.

Способ №1 - руками переопределить метод toString и, с помощью этого класса, описать способ конструирования строкового отображения объектов. Ничего особо примечательного здесь нет, за исключением удобства, которое добавляет упомянутый ToStringBuilder.

    @Override
    public String toString() {
        return new ToStringBuilder(this)
          .append("title", title)
          .append("author", author)
          .append("price", price)
          .append("date", publDate)
          .toString();
      } 


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

Способ №2 интереснее - он использует reflection. В этом случае мне достаточно вызвать ToStringBuilder.reflectionToString(мой-объект), не занимаясь перечислением имён полей и их значений вручную.

Например, для такого случая

  Book book = new Book();
  book.setAuthor("Gregory M.");
  book.setTitle("The Secret Book of Secrets");
  book.setPrice(15.03);
  book.setPublDate(null); // это специально, чтобы явно показать null-значение


вызов

  System.out.println(ToStringBuilder.reflectionToString(book));

вернёт такой вот результат:
>>> javaapplication243.Book@10b30a7[title=The Secret Book of Secrets,author=Gregory M.,price=15.03,publDate=] 

Да, вот эти >>> я добавил в результат сам, для удобства (моего) при чтении.

Есть несколько способов повлиять на формат получаемого результата.
Результат, показанный чуть выше, получен при использовании формата, используемого по-умолчанию. Имя этого формата - DEFAULT_STYLE.

Можно руками, вызвав статический метод, указать формат, который я хочу использовать:
  
  ToStringBuilder.setDefaultStyle(ToStringStyle.MULTI_LINE_STYLE);

А можно указать нужный формат явным образом, например, вот так:

  ToStringBuilder.reflectionToString(book, ToStringStyle.MULTI_LINE_STYLE)      

Теперь самое интересное - какие форматы есть и как они влияют на результат.

DEFAULT_STYLE
>>> javaapplication243.Book@10b30a7[title=The Secret Book of Secrets,author=Gregory M.,price=15.03,publDate=]  

MULTI_LINE_STYLE
>>> javaapplication243.Book@10b30a7[
      title=The Secret Book of Secrets
      author=Gregory M.
      price=15.03
      date=
    ]


SHORT_PREFIX_STYLE
>>> Book[title=The Secret Book of Secrets,author=Gregory M.,price=15.03,publDate=]

NO_FIELD_NAMES_STYLE
>>> javaapplication243.Book@10b30a7[The Secret Book of Secrets,Gregory M.,15.03,]

SIMPLE_STYLE
>>> The Secret Book of Secrets,Gregory M.,15.03,         

среда, апреля 14, 2010

Составной первичный ключ из двух FK

Встретился несколько необычный случай отображения данных.
На картинке показаны соответствующие таблицы.





В EVENT_KIND содержится список каких-то видов событий, а в VALID_EVENT_KIND - список допустимых сочетаний "предыдущий вид события" - "следующий тип события".

Если работа с EVENT_KIND типична и ничего интересного не представляет, то вот случай с VALID_EVENT_KIND - интереснее.
Классогенератор Netbeans отказыватеся генерировать для этой таблицы соответствующий Entity, резонно, в некотором смысле, сообщая о том, что это ведь обычная таблица связи (для отношения многие-ко-многим), а поэтому и сущность соответствующая не нужна. А раз не нужна, то и делать не буду (упорный, блин).

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

Итак, раз для нас код сгенерировать отказались, остаётся написать его самому. К счастью, особо тут и писать нечего.

Вот так выглядит класс, соответствующий VALID_EVENT_KIND

@Entity
@Table(name="VALID_EVENT_KIND")
public class ValidEventKind implements Serializable {

    @EmbeddedId
    private ValidEventKindPk pk;

    public ValidEventKind() {}

    public ValidEventKind(EventKind prevEvent, EventKind nextEvent) {
        this.pk = new ValidEventKindPk(prevEvent, nextEvent);
    }
}
Ничего интересного, за исключением @EmbeddedId.
А вот и описание самого первичного, embedded-ного, ключа:

@Embeddable
public class ValidEventKindPk implements Serializable {
    @ManyToOne()
    @JoinColumn(name="prev_event", referencedColumnName="code")
    private EventKind prevEventKind;

    @ManyToOne
    @JoinColumn(name="next_event", referencedColumnName="code")
    private EventKind nextEventkind;

    public ValidEventKindPk() { }

    public ValidEventKindPk(EventKind prevEventKind, EventKind nextEventKind) {
        this.prevEventKind = prevEventKind;
        this.nextEventkind = nextEventKind;
    }
}
Разные getters и setters в обоих классах я, очевидное дело, опустил.

Вот и всё...

среда, апреля 07, 2010

Grails - generate-controller и ошибка 404

Создал новое приложение.
Добавил domain-класс Album.
Добавил контроллер, установил ему scaffold.
Всё работает. Приложение запускается, ссылка на контроллер показывается, переход по ссылке переходится.

Теперь я не хочу больше scaffold. Я говорю: а сделай мне generate-controller. Делает.

Запускаю приложение снова. Кликаю по ссылке на контроллер и наблюдаю ошибку:

HTTP Status 404 - /GrailsApplication2/WEB-INF/grails-app/views/album/list.jsp
type Status report
message /GrailsApplication2/WEB-INF/grails-app/views/album/list.jsp
description The requested resource (/GrailsApplication2/WEB-INF/grails-app/views/album/list.jsp) is not available.

Вот этот самый jsp, если честно, меня озадачил.

В итоге определилась причина пробелмы: не были сгенерированы представления (view по-нашему).
Поэтому говорю: generate-views для своего класса - и всё становится ОК.

Netbeans, пусть к JDK

Уже не в первый раз после переустановки JDK соображал, как указать Netbeans на новое её местоположение. Дело в том, что при загрузке он ищет её (или его?) по старому месту, и, не обнаружив, ругается.

Так как каждый раз разбираться заново мне надоело, решил записать.

Путь к JDK указывается в netbeans.conf, который живёт в каталоге INSTALL_DIR/etс:

netbeans_jdkhome="D:\DevTools\Java\jdk1.6.0_19"

Grails - ошибка в синтаксисе команды

Запускаю из коммандной строки grails - получаю сообщение "Ошибка в синтаксисе команды".
Подумал - дистрибутив неправильный может? Нет, нормальный, нетбинзу нравится.

Оказалось: не установлен GRAILS_HOME.

Установил - заработало.

суббота, февраля 20, 2010

Обновился список из Top 25 Most Dangerous Programming Errors

17 февраля обновился список 25 самых опасных ошибок в софтостроении:
2010 CWE/SANS Top 25 Most Dangerous Programming Errors

Вот эти вещи признаны самыми опасными:
[1] Failure to Preserve Web Page Structure ('Cross-site Scripting')
[2] Improper Sanitization of Special Elements used in an SQL Command ('SQL Injection')
[3] Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
[4] Cross-Site Request Forgery (CSRF)
[5] Improper Access Control (Authorization)
[6] Reliance on Untrusted Inputs in a Security Decision
[7] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
[8] Unrestricted Upload of File with Dangerous Type
[9] Improper Sanitization of Special Elements used in an OS Command ('OS Command Injection')
[10] Missing Encryption of Sensitive Data
[11] Use of Hard-coded Credentials
[12] Buffer Access with Incorrect Length Value
[13] Improper Control of Filename for Include/Require Statement in PHP Program ('PHP File Inclusion')
[14] Improper Validation of Array Index
[15] Improper Check for Unusual or Exceptional Conditions
[16] Information Exposure Through an Error Message
[17] Integer Overflow or Wraparound
[18] Incorrect Calculation of Buffer Size
[19] Missing Authentication for Critical Function
[20] Download of Code Without Integrity Check
[21] Incorrect Permission Assignment for Critical Resource
[22] Allocation of Resources Without Limits or Throttling
[23] URL Redirection to Untrusted Site ('Open Redirect')
[24] Use of a Broken or Risky Cryptographic Algorithm
[25] Race Condition