SoapUI and SSLPeerUnverifiedException

I have developed and tested new web service. I used SoapUI for testing local endpoint. Next step was to deploy the service into testing environment. But suddenly I failed to connect to this endpoint. I was able to open its WSDL description in Firefox, but SoapUI failed with SSLPeerUnverifiedException: peer not authenticated. The setup was network with proxy and there was Apache proxy translating URLs for the service. There was many similar complaints on web but no solution. I tried many proposals like trusting the certificate (because StartCom is not trusted certification authority in Java) but nothing helped. Until I posted a question SoapUI fails to connect HTTPS (SSLPeerUnverifiedException) on StackOverflow. It lead me to solution:

  1. edit bin/soapui.bat
  2. find setting the property JAVA_OPTS
  3. append -Djsse.enableSNIExtension=false

The reason for this behavior is explained in this answer:

Java 7 introduced SNI support which is enabled by default. I have found out that certain misconfigured servers send an „Unrecognized Name“ warning in the SSL handshake which is ignored by most clients… except for Java.

OAuthLogin – beta testing

No public interest, so I discontinued this project

I have an idea of writing new website and I know that people do not like registrations. To maximize user involvement and participation I decided to support OAuth login technology which delegates authentication and authorization to different provider. In other words you can safely login with Google, Facebook and many other service accounts. I found Scribe library that helps Java developers but I realized that it is not such easy to start. So I decided to write a prototype first to learn all neccessary technologies in advance. And once it progressed and I put more effort in it I decided to make it public and open source.

So there it is. It is beta release which improved user experience and fixed too broad privileges issue. It is standalone Java Enterprise application consisting of two modules: EJB and WAR. The users are persisted in database via JPA. The users can log with Google, Twitter and Facebook. I reconsider Microsoft account support as well. It is possible to log with one provider and then link other providers as well, so you can later choose any provider to log into same account.

GitHub

 

Malý testík pro programátory

Dámy a pánové, programátoři všeho věku, leč se zaměřením na Javu, mám pro vás jednoduchý úkol na pozdní večer. Už vás nudí číst si cvrlikání na twitteru nebo tlachání na facebooku? Politiky na rádoby důvěryhodné idnes máte plné zuby? Zkuste si zahrát na programátory bankomatu. Zjednodušenou formu najdete na adrese http://37.205.9.68/hiring/ a jestli uspějete, možná si to vyzkoušíte doopravdy :-).

Working with complex database types in WebLogic

My colleague asked me for help with a project, where java layer prepared data and passed it to a database layer, where PL/SQL functions awaited it. Some functions expected standard types like VARCHAR or NUMBER and implementation was smooth. But few functions expected complex database type on its input – table of types that reference other types. It took me some time to figure it out (StackOverflow question), how to prepare data and connection correctly. And I have learned several lessons I want to share in this article.

Let me introduce the example I will present here. There is a table Person with attributes name, surname, age and flag vip. The package oracle_types has two methods: get and add. The get method returns Antonín Holý record, the add method will store new entry into Person table with flag vip set when there is a keyword ‚actor‘ set.

CREATE TABLE PERSON (
    name    VARCHAR2(20),
    surname VARCHAR2(30),
    age     NUMBER(3),
    vip     CHAR(1)
);

CREATE OR REPLACE TYPE keyword_rec IS OBJECT (
    value VARCHAR2(20)
);

CREATE OR REPLACE TYPE keywords_rec IS TABLE OF keyword_rec;

CREATE OR REPLACE TYPE person_rec IS OBJECT (
    name     VARCHAR2(20),
    surname  VARCHAR2(30),
    age      NUMBER(3),
    keywords keywords_rec
);

CREATE OR REPLACE PACKAGE oracle_types AS
  FUNCTION add(p_rec person_rec, p_message OUT VARCHAR2) RETURN PLS_INTEGER;
  FUNCTION get RETURN person_rec;
end oracle_types;
/

CREATE OR REPLACE PACKAGE BODY oracle_types IS
  FUNCTION add(p_rec person_rec, p_message out varchar2) RETURN PLS_INTEGER IS
   v_vip NUMBER := 0;
  BEGIN
    FOR cur IN 1 .. p_rec.keywords.LAST
    LOOP
      IF p_rec.keywords(cur).value = 'actor' THEN
        v_vip := 1;
      END IF;
    END LOOP;
      IF v_vip > 0 THEN
        INSERT INTO PERSON(name,surname,age,vip) VALUES (p_rec.name, p_rec.surname, p_rec.age, '1');
      ELSE
        INSERT INTO PERSON(name,surname,age,vip) VALUES (p_rec.name, p_rec.surname, p_rec.age, '0');
      END IF;
   RETURN 1;
  END;

  FUNCTION get RETURN person_rec IS
   v_person person_rec;
   v_keywords keywords_rec;
  begin
    v_keywords := keywords_rec();
    v_keywords.EXTEND(2);
    v_keywords(1) := keyword_rec('scientist');
    v_keywords(2) := keyword_rec('inventor');
    v_person := person_rec('Antonin', 'Holy', 75, v_keywords);
    RETURN v_person;
  END;

BEGIN
  NULL;
end oracle_types;
/

declare
 v_result person_rec;
begin
  v_result := oracle_types.get();
  dbms_output.put_line('name = '||v_result.name);
  dbms_output.put_line('surname = '||v_result.surname);
  dbms_output.put_line('age = '||v_result.age);
  for cur in 1 .. v_result.keywords.last
  loop
    dbms_output.put_line('keyword = '||v_result.keywords(cur).value);
  end loop;
end;
/

The types must be public and they cannot be declared inside the package. Otherwise java will not see them. The java side will reside in WebLogic, so we need a remote interface for our business logic:

@Remote
public interface IOracleTest {
    public void performGet() throws Exception;
    public void performCall() throws Exception;
}

The stateless session bean implements this interface. It needs an access to database, so I declared datasource and let the application server to inject it.

@Stateless(mappedName = "test/oracle")
public class OracleTest implements IOracleTest {
    private static final Log log = LogFactory.getLog(OracleTest.class);

    @Resource(name = "jdbc/test")
    protected javax.sql.DataSource datasource;

The data source is to be created in Services/Data Sources menu option and JNDI name must match java resource name.

weblogic-ds

I will describe add method, because it is more complex – you need to construct an object tree the way that Oracle database expects. You must register your types in database connection. If the type is not public and it is located in different schema than your JDBC connection uses, you must prefix it with schema name.

conn = datasource.getConnection();
ArrayDescriptor keywordsArrayDesc = ArrayDescriptor.createDescriptor("KEYWORDS_REC", conn);
StructDescriptor personStructDesc = StructDescriptor.createDescriptor("PERSON_REC", conn);

The next step is to create array for person’s keywords. We have two rows with single column for KEYWORDS_REC type. The dimensions must be exactly the same like in database, otherwise an exception will occur. You have to pass objects that Oracle understands: String, BigDecimal, java.sql.Date etc. It is painfull to investigate, which object it does not like, because Oracle exceptions does not contain any identification of invalid value (SQLException: Inconsistent java and sql object types).

Object[][] keywordsAttribs = new Object[2][1];
keywordsAttribs[0][0] = "actor";
keywordsAttribs[1][0] = "producer";

Ok, it is time to prepare object for database procedure call. The person consists of four columns, therefore we need to create array of four objects. The last column is the table of KEYWORD_REC types. So we instantiate Oracle ARRAY object with two dimensional array and identification of used type (ArrayDescriptor keywordsArrayDesc). And we put it all together into Oracle STRUCT, again with type identification passed by StructDescriptor.

Object[] personAttribs = new Object[4];
personAttribs[0] = "Christian";
personAttribs[1] = "Bale";
personAttribs[2] = 39;
personAttribs[3] = new ARRAY(keywordsArrayDesc, conn, keywordsAttribs);
STRUCT struct = new STRUCT(personStructDesc, conn, personAttribs);

The last preparation step is to prepare database call. Our PL/SQL function returns two values, so we will specify their position. Again, if the position or returned type does not match database, SQLException will be raised.

prepStmt = conn.prepareCall("{ ? = call oracle_types.add(?, ?)}");
prepStmt.registerOutParameter(1, Types.INTEGER);
prepStmt.registerOutParameter(3, Types.VARCHAR);
prepStmt.setObject(2, struct);

Finally we will execute the statement and get the out variables.

prepStmt.execute();
int returnCode = prepStmt.getInt(1);
String message = prepStmt.getString(3);

The get method is very similar and I will leave it uncommented. Just one note – you need to have orai8n.jar in your classpath otherwise UTF conversion will not occur and fetched string will be unreadable.

conn = datasource.getConnection();
cs = conn.prepareCall(sql);

StructDescriptor keywordStructDesc = StructDescriptor.createDescriptor("KEYWORD_REC", conn);
StructDescriptor personStructDesc = StructDescriptor.createDescriptor("PERSON_REC", conn);
ResultSetMetaData metaData = personStructDesc.getMetaData();
cs.registerOutParameter(1, Types.STRUCT, "PERSON_REC");
cs.execute();

STRUCT output;
Object recordTmp = cs.getObject(1);
if (recordTmp instanceof Struct){
    output = (oracle.sql.STRUCT)(((weblogic.jdbc.wrapper.Struct)recordTmp).unwrap(Class.forName("oracle.sql.STRUCT")));
} else {
    output = (oracle.sql.STRUCT)recordTmp;
}

Object[] data = output.getAttributes();
int idx = 1;
for (Object tmp : data) {
    log.info(metaData.getColumnName(idx++) + " = " + tmp + ",---");
}

All the source code plus executable ear application is attached. To compile, you will need to provide listed jars.

PS I am interested how portable JDBC implementation would look like. Please comment code differences in Java.

Vzkaz junior personalistům

Inspirací pro tento zápisek byl článek Ako personalisti vnimaju ajtakov. Ale já to vezmu z opačné strany, jaké chování a nabídky se mi nelíbí. Typicky přichází od začátečníků, i když přidávání do linkedin kontaktů zkoušejí snad všichni. Asi to mají v manuálu, nebo je to učí na škole.

Nerelevantní nabídky

Drazí head hunteři, pokud si někde vygooglujete moje jméno, snažte se prosím přečíst, čím se zabývám a jak jsem daleko v kariéře. Co si asi mám myslet, když dostanu email s nabídkou desíti pracovních pozic od administrátora windows po vývojáře v dot net, zatímco se pohybuju v oblasti J2EE v manažerských pozicích? Tohle je na úrovni spamu, i robot by dokázal cílit lépe. A pro dokreslení, nabídka přišla z freemailové adresy s textem, že jde o renomovanou agenturu (která ale raději nebyla jmenována). Pokud nejste z IT a termínům z předešlého odstavce nerozumíte, dovolím si překlad: přišla mi nabídka, zda nemám zájem o některou pozici: zedník, elektrikář, prodavačka v supermarketu, právník, kadeřnice, architekt či řidič traktoru.

O něco menší faux paix je, když mi přijde nabídka dělat programátora. Personalista si přečte moje CV, poslední tři pozice za více než 6 let jsou řídící, pak pokračuje do ještě větší historie a najde moje začátky s klíčovými slovy, které si přečetl v profilu hledané pozice. Okamžitě zajásá a posílá mi nabídku juniorské pozice s polovičním platem. Oops, těsně vedle.

Kontaktování

Pracovní profil si vedu na linkedin. Mám na něm uveden email. Přesto většina nabídek začíná tím, že mi přijde požadavek, abych si dotyčného přidal do linkedin kontaktů. Já se snažím mít v kontaktech jen lidi, se kterými jsem byl v osobním kontaktu. Tedy kolegy a ex-kolegy, business partnery a klienty. Když mi přijde požadavek od někoho, koho neznám, je mi nepříjemné psát vysvětlující email, proč jej odmítám. Většinou to zabere dost času, než se mi text zdá ne-arogantní. Proto, abych si přečetl vaše doporučení, opravdu není zapotřebí přidávat si vás mezi obchodní partnery. Stačí starý dobrý email. Díky.

Displaying binary value of byte

During my fights with 7z format I realized a need to see a value of byte in binary representation. Unfortunatelly there is no good way in Java, how to display binary value for the byte primitive. The method Integer.toBinaryString() takes int as its argument and a conversion byte to int does not work well for negative numbers. Following code will print a range of byte values:

public class Test {
    public static void main(String[] args) {

        byte b = -127;
        for (int i = 0; i < 255; i++) {
            System.out.println(String.format("%4d = 0x%02X = ", b, b) + printBinary(b));
            b++;
        }
    }

    public static String printBinary(byte number) {
        StringBuilder sb = new StringBuilder(8);
        for (int i = 8; i-- > 0;) {
            sb.append(((number & (1 << i)) != 0) ? 1 : 0);
        }
        return sb.toString();
    }
}