Blog

  • Petrův svět

    Petr vstal a proletěl se. Bylo to tak osvěžující vyskočit z okna a vzlétnout k oblakům. Měl na sobě podobu malého vrabčáka. Miloval ten pocit, když mu vítr čechral jeho šedavé peří. Prohrábl si krátkým zobákem hnědá pírka a vydal se vzhůru. Za chvíli byla země již maličká a vzdálená. Cítil dokonalou svobodu a volnost, která se mísila s pocity dokonalého štěstí. Najednou ale na Petra znovu přišel ten známý pocit nebezpečí. Neviděl jej, neslyšel jej, ale věděl, že něco není v pořádku. Instinktivně se vrhl střemhlav dolů k zemi a v zápětí jej dostihl stín. Uslyšel aerodynamický svist rychle se blížícího dravce. Dovolil si krátké ohlédnutí – jestřáb! Nemá šanci uniknout jeho ostrým pařátům a špičatému zobáku, kterým jej brzy roztrhá na kusy. Petr musí reagovat okamžitě, jako vrabec nemá šanci. Už cítil dravcovu blízkost, když Petr změnil svou podobu na kámen. Jestřáb přejel drápy po kameni, až se zajiskřilo a kámen mu vyklouzl. Stejně už o něj neměl zájem. Zastavil se a chvíli pozoroval, jak kámen narůstající rychlostí padá k zemi a boří se do hlíny. Pak se jestřáb elegantně otočil a odletěl zpět k osamělé lípě na louce, odkud bude vyhlížet jinou kořist.

    Kámen chvilku ležel v hlíně a nehýbal se. Trpělivě čekal, zda se nebezpečí nevrátí. Po chvilce ale začal být Petr netrpělivý a proměnil se na mravence. Chtěl být maličký, aby si jej nikdo nevšiml. Vždycky slýchával o obrovské mravenčí síle a rozhodl se ověřit si tyto zkazky v praxi. Uviděl stvol šťovíku a přispěchal k němu. Zvláštní, jako mravenec měl puzení neustále pospíchat. Zaťal svá silná kusadla do stvolu a ucítil pronikavou až pichlavě kyselou chuť. Jako člověk ji měl rád, ale pro mravence byl šťovík nepoživatelný. Škoda.

    Porozhlédl se kolem sebe. O kousek dál se k nebi čněla obrovská pampeliška. Připadala mu jako obrovský strom, který sahá až k oblakům. Ani na okamžik neváhal a už si rázoval nahoru. Šlo mu to výtečně, šest nohou mu poskytovalo dokonalou oporu a bez nejmenší námahy se rychle dostal až ke květu. Tam uslyšel pomalý, hluboký a hlasitý zvuk. Na chvilinku se polekal, ale pak mu to došlo – je to jen včela, ta mu neublíží. Protáhl se hustým žlutým houštím a celý se umazal od pylu. Nakoukl přes okraj – to byl pohled. Louka je z hmyzí perspektivy nádherná, neskutečně pestrá a divoká. Vítr přistávající včely málem mravence smetl dolů. Petr na nic nečekal, naskočil na včelí nohu a pevně se zapřel. Včela se jej snažila setřást, Petr se ale nedal a seskočil, až když včela odletěla o kus dál. Pro člověka by to byla krátká procházka, ale jako mravenec by sem šel celé odpoledne.

    Petra začal trápit hlad a žízeň. Na dohled dováděla malá polní myška. Z Petrova pohledu to však byla obrovská páchnoucí pohyblivá hora. Samozřejmě jako mravenec si na ni troufnout nemohl, ale stačilo jen pomyslet a z mravence se stal šedý, černě žíhaný kocour. Pro myšku to byl šok, nemohla pochopit tu proměnu a nedostala ani příležitost nad ní více dumat, neboť Petr okamžitě napnul svaly v zadních nohou a skočil. Dopadl těsně u myšky a drápky pravé packy zaťal do myšky. A hned je zase vytáhnul. Takové vítězství jej neuspokojovalo, chtěl cítit vzrušení lovu a dát myšce falešnou iluzi, že si může zachránit život.

    Sundal packu. Myška na nic nečekala a pelášila pryč. Kocour se zase přikrčil a myšku snadno předskočil. Ta prudce zabočila a zamířila ke své noře, která byla jen půl metru daleko. Kocour však lehce natáhl přední nohu a tlapkou lehce uhodil ze strany do myšky, která se překulila a ztratila směr. Myška se nesmířila se svou situací a utíkala od kocoura pryč, bylo jí jedno kam. Petr chvilinku čekal a pak třemi krátkými skoky myšku dohonil a opět do ní zaťal drápky. Netušil proč, ale tahle hra jej bavila. Myška už ztrácela síly a po dvou dalších nepovedených útěcích se jen schoulila a čekala, co se bude dít. Kocoura už myška začala nudit a tak ji ukousl hlavu. Slízal vytékající krev a myšku pomalu snědl. Pak se pomalu přesunul na slunné místo, lehnul si a začal si olízávat srst, kterou si během honičky s myškou zašpinil.

    Už pěknou chvíli odpočíval, sluníčko se pomalu začínalo klonit k západu, když opět vycítil ZLO. Naježily se mu chlupy na zádech. Nastražil uši a čenichal. Věděl, že tu je, ale smysly mu neukázaly kde. Náhle ucítil jemné otřesy půdy. Jeden, druhý, třetí, čtvrtý. Dva lidé jdou po louce. Přikrčil se a opatrně se plížil do vysoké trávy, kde jej nebudou moci zahlédnout, zatímco on je bude moci z bezpečné vzdálenosti pozorovat. Konečně je zahlédl – a ustrnul. Mami, tati, chtěl vykřiknout, místo toho mu z úst vyklouzlo jen zamňoukání. Přeměnil se zpět do své chlapecké podoby a běžel jim v ústrety. Ale oni jej neviděli, opět. Kouzlo stále nepominulo, jeho rodiče jej nevnímali. Stál před nimi, křičel na ně, mával jim rukama před očima, ale byli hluší a slepí. Petr se rozplakal.

    Udělal by cokoliv, jen aby zlomil to prokletí. Jeho rodiče vypadali strašně smutně a matce řinuly slzy po její vráskami zbrázděné tváři. Otec ji pevně držel kolem ramen a nepatrně se chvěl. Nedalo se nic dělat, nevnímali Petra, ať se snažil sebevíc. Nemohl jim pomoci. Petr si klekl na kolena, dal si tváře do dlaní a plakal. Chtěl by zase být se svými rodiči, ale oni byli začarovaní. Potkával je každý den už nespočetné měsíce, ale pokaždé to dopadlo stejně. Jen maminka byla při každé návštěvě smutnější a starší. Bylo vidět, jak se Petrovi rodiče s někým baví, Petr ale neviděl s kým. Nikdy jej neviděl, ale bál se jej. Najednou ucítil chlad. Celý se roztřásl zimou. Začalo se rychle šeřit. A pak už byla jen tma. Petr chtěl vykřiknout, ale cítil se tak unavený.

    Epilog

    Lékař tiše řekl: „Udělali jste dobře, Petr je už stejně půl roku mrtvý. Je mi to moc líto, ale po té tragické nehodě neměl šanci. Nemělo smysl nechávat jej dále napojeného na přístroje. Nebyla naděje na zlepšení. Jeho já nás už dávno opustilo. Děkuji, že jste mu dali příležitost důstojně umřít“.

  • Duplicate entry in a form

    I have seen several forms recently that requested user to enter some information twice. It makes sense to retype the password that user has chosen. It reduces a risk that user does typo and newly created account will be unaccessible. But these forms asked the user to retype his email address or existing password. The email address is displayed unlike password, so the risk of typo is quite small. But I can imagine that developer thinks that this email is so important to force the user to enter the same information twice. To retype existing password is totally useless. If the user enters his password incorrectly, just redisplay the form. Please when you design some form with duplicated entry of some field, ask yourself – is it really neccessary to bother the user?

  • Tips on installing MS SQL 2012 Express edition

    Well, I was once again forced to use another Microsoft product – their database this time. And it took me several hours to make it work, so I want to share some details in hope, that it will be helpfull to you.

    The installation was smooth but later I realized that I cannot contact this database from java. Why? TCP IP was disabled by default. This is very secure option, yet I can imagine more secure one – switch the computer off. Stop kidding. Open SQL Server Configuration Manager, open Network configuration from left tree and select Protocols node. There you need to enable TCP/IP protocol, open its properties dialog and change the property Enabled to true.

    TCP/IP protocol properties

    Dis is one half. Oh no, it is back! (Who does understand this joke?)

    If you try to connect this new database, you will fail again. MS SQL will play a game Guess my port with you. Ok, they have some naming service and some good reasons for this behaviour, but let keep things simple and switch off dynamic ports feature. Choose IP addresses tab. Either modify one concrete network interface or find the last section IP All. Delete value in the option TCP Dynamic Ports and set 1433 to the option TCP Port. Finally you have to restart MS SQL service.

    Default value with dynamic portupdated value to MS SQL default portRestarting MS SQL service

    Stop, we are not finished yet. You do not want to use your windows credentials and probably store them somewhere in configuration files, do you? So it is time to switch off Windows Authentication mode. Open MS SQL Management Studio, edit server properties, Security page particularly. There you need to select mixed mode – both SQL Server and Windows Authentication modes in Server authentication section.

    Selecting authentication mode

    And finally create some user with appropriate roles. It is neccessary to be DDL admin and DB owner for development purposes. Restart MS SQL

    Adding new user

    Some useful links I used:

    Blog bitcoin address: 1GQBYqZwiHT72UrLCCSv4j6WkK65FjTPJk

  • 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.

    Blog bitcoin address: 1GQBYqZwiHT72UrLCCSv4j6WkK65FjTPJk

  • 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.

  • Comments in this blog

    When I returned from my vacation, I realized there were 30 comments in my blog waiting for approval. Some were very easy to recognize as spam. But other looked naturally on the first read. Until I found that it is not probable that english reader would enjoy czech written story.

    Then there were comments to my english written story. They looked fine, but author had URL containg commercial keywords (louis vuiton, ray bean, social stocks ..) – I marked them as spam as well. Finally there were few remaining comments, where I had to open author URL and guess, if they were posted by person or spam software. Thank you for your comments, I like them. Sorry if I was wrong and removed your real comment.

    I will have to spend some time and search for better wordpress comments solution. Facebook comments might be safe against spammers but I do not want to limit my readers that do not use it. The current solution is too weak, some captcha filter is unfortunatelly neccessary.

    PS very nice web spam description