[{"content":" What it does # In GTK apps such as Pluma, Ctrl+. opens a popup with emojis. The Eclipse editor does not have this popup. There, you can only type Ctrl+Shift+U and the hex code of the emoji, so you must know the code.\nThis plugin adds the popup to all Eclipse text editors: Java, XML, plain text and the others.\nPress Alt+Shift+. (Option+Shift+. on macOS), or select Edit \u0026gt; Insert Emoji\u0026hellip; Type a name to search, for example fish or cat face. Use the arrow keys or the mouse to select an emoji. Press Enter or click to insert it. Press Esc to close the popup. The buttons at the bottom go to a group: smileys, people, animals, food, travel, activities, objects, symbols and flags. Recently used emojis show first. Ctrl+Z removes an inserted emoji, as for typed text. Install # In Eclipse, select Help \u0026gt; Install New Software\u0026hellip;\nIn Work with, type this address and press Enter:\nhttps://anydoby.com/eclipse Select Emoji Picker in the category anydoby Eclipse plugins.\nClick Next, accept the license (EPL-2.0) and click Finish.\nRestart Eclipse.\nThe plugin needs Eclipse 2024-03 (4.31) or later.\nNotes # To change the key, go to Window \u0026gt; Preferences \u0026gt; General \u0026gt; Keys and search for \u0026ldquo;Insert Emoji\u0026rdquo;. In the Emacs key scheme, Alt+Shift+. already means \u0026ldquo;go to text end\u0026rdquo;. Save files that contain emojis as UTF-8. Older workspaces on Windows can use Cp1252, which changes emojis into question marks. The popup shows each emoji in its default skin tone. The emoji list is Unicode 15.1. The plugin uses the emoji font of the system: Noto Color Emoji on Linux, Segoe UI Emoji on Windows and Apple Color Emoji on macOS. On Windows, Eclipse can show emojis in black and white. Changelog # 1.0.1: new plugin ID com.anydoby.emojipicker. If you installed 1.0.0, uninstall it first (Help \u0026gt; About Eclipse IDE \u0026gt; Installation Details). 1.0.0: first release ","date":"30 October 2026","externalUrl":null,"permalink":"/plugins/emoji-plugin/","section":"Eclipse plugins","summary":"","title":"Emoji Picker","type":"plugins"},{"content":"","date":"30 October 2026","externalUrl":null,"permalink":"/tags/eclipse/","section":"Tags","summary":"","title":"Eclipse","type":"tags"},{"content":"Plugins 🔌 for the Eclipse IDE. Each page has a description, screenshots and the update site URL.\n","date":"30 October 2026","externalUrl":null,"permalink":"/plugins/","section":"Eclipse plugins","summary":"","title":"Eclipse plugins","type":"plugins"},{"content":"","date":"30 October 2026","externalUrl":null,"permalink":"/","section":"Home","summary":"","title":"Home","type":"page"},{"content":"","date":"30 October 2026","externalUrl":null,"permalink":"/tags/plugin/","section":"Tags","summary":"","title":"Plugin","type":"tags"},{"content":"","date":"30 October 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"17 October 2026","externalUrl":null,"permalink":"/articles/","section":"Articles","summary":"","title":"Articles","type":"articles"},{"content":"","date":"17 October 2026","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"The old site — Tomcat, Firebird, a Raspberry Pi 1 — is gone. As they say, good admins back up their sites, real admins also restore from the backups. In my case a restore exercise went awry and the whole of my hard work went to the land of eternal hunting. This one is plain static HTML generated by Hugo and served by Caddy from a Raspberry Pi 4.\nI\u0026rsquo;ll try to write something on a regular basis. Nowadays a decent LLM can write something every day for me, but I wont fall into that trap (hopefully).\nWhat they can do is write code which I otherwise would not write (because you don\u0026rsquo;t have infinite free time at the end of the day), and that transforms into usable stuff, mainly for the IDE I\u0026rsquo;m using at work.\n","date":"17 October 2026","externalUrl":null,"permalink":"/articles/hello-again/","section":"Articles","summary":"","title":"Hello again","type":"articles"},{"content":"","date":"17 October 2026","externalUrl":null,"permalink":"/tags/meta/","section":"Tags","summary":"","title":"Meta","type":"tags"},{"content":"","date":"17 October 2026","externalUrl":null,"permalink":"/tags/raspberry-pi/","section":"Tags","summary":"","title":"Raspberry-Pi","type":"tags"},{"content":"","date":"17 October 2026","externalUrl":null,"permalink":"/categories/site/","section":"Categories","summary":"","title":"Site","type":"categories"},{"content":"","date":"17 December 2020","externalUrl":null,"permalink":"/tags/java/","section":"Tags","summary":"","title":"Java","type":"tags"},{"content":"","date":"17 December 2020","externalUrl":null,"permalink":"/categories/jblog/","section":"Categories","summary":"","title":"Jblog","type":"categories"},{"content":"I know, it\u0026rsquo;s tough to test for impossible situations. Especially testing the default case of your switch :) like this one.\nswitch (animal) { case: CAT: // do cat stuff break; case: DOG: // do dog stuff break; default: throw new IllegalArgumentException(\u0026#34;Dunno what to do\u0026#34;); } Imagine someone introduces a new enum that\u0026rsquo;s not handled and forgets to add a new case.\nUnfortunately Mockito does not allow creating a mock for enum, so here comes Powermock. I\u0026rsquo;m not a big fan of mocks and especially those that mock static methods, I think it\u0026rsquo;s a bad smell. However mocking enums for testing illegal or default cases is just that single spot where it makes sense.\nSo to begin with let\u0026rsquo;s add these dependencies to our project:\n\u0026lt;powermock.version\u0026gt;2.0.9\u0026lt;/powermock.version\u0026gt; ..... \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.powermock\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;powermock-module-junit4\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${powermock.version}\u0026lt;/version\u0026gt; \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.powermock\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;powermock-api-mockito2\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${powermock.version}\u0026lt;/version\u0026gt; \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; Then we need to mock enum before the test class is loaded. It\u0026rsquo;s a bit tricky and involves messing with JDK internals. Different JDK versions have different names for enum values constant within the Enum class.\n@BeforeClass public static void prepareEnum() { int optionsLength = Animal.values().length; Animal[] newAnimals = new Animal[optionsLength + 1]; System.arraycopy(Animal.values(), 0, newAnimals, 0, optionsLength); strangeAnimal = PowerMockito.mock(Animal.class); Whitebox.setInternalState(strangeAnimal, \u0026#34;name\u0026#34;, Integer.toString(optionsLength)); Whitebox.setInternalState(strangeAnimal, \u0026#34;ordinal\u0026#34;, optionsLength); newAnimals[optionsLength] = strangeAnimal; try { // works in eclipse Whitebox.setInternalState(Animal.class, \u0026#34;ENUM$VALUES\u0026#34;, newAnimals); } catch (Exception e) { // some JDK\u0026#39;s put these in different field Whitebox.setInternalState(Animal.class, \u0026#34;$VALUES\u0026#34;, newAnimals); } } In the code above we create a mock enum with the help of bytecode manipulation and then replace values array in our enum class (in order for the switch to work correctly). Different JDK\u0026rsquo;s have different name for this array. Maybe your will have yet another one :)\nYou might also want to write separate test classes for \u0026ldquo;regular\u0026rdquo; enum values and the illegal one, since if you only test normal cases in the \u0026ldquo;powered\u0026rdquo; unit tests the normal enum class will have zero coverage (after all Jacoco will see reference to the generated class).\nHere\u0026rsquo;s the link to a Github project with this exercise.\nFirst published on the old anydoby.com blog on 2020-12-17.\n","date":"17 December 2020","externalUrl":null,"permalink":"/articles/mocking-enums-in-java-to-increase-code-coverage/","section":"Articles","summary":"","title":"Mocking enums in Java to increase code coverage","type":"articles"},{"content":"The job of an IT consultant is at times dangerous and sweaty. Apart from the bleeding edge tech you have to deal with the bloody legacy enterprise. Some time ago I had to adapt a web application to run within an IBM WebSphere 8.x.\nThe application is a simple bunch of web services which runs normally in a servlet container. Regular Spring + CXF with SOAP services, but when packed into an ear archive and installed into a full fledged application container it boomed:\nCaused by: org.apache.cxf.bus.extension.ExtensionException: Could not load extension class org.apache.cxf.ws.policy.AssertionBuilderRegistryImpl. at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:183) at org.apache.cxf.bus.extension.Extension.getClassObject(Extension.java:199) at org.apache.cxf.bus.extension.ExtensionManagerImpl.activateAllByType(ExtensionManagerImpl.java:144) at org.apache.cxf.bus.extension.ExtensionManagerBus.\u0026lt;init\u0026gt;(ExtensionManagerBus.java:179) at org.apache.cxf.bus.extension.ExtensionManagerBus.\u0026lt;init\u0026gt;(ExtensionManagerBus.java:191) at org.apache.cxf.bus.spring.SpringBus.\u0026lt;init\u0026gt;(SpringBus.java:45) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:86) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:58) at java.lang.reflect.Constructor.newInstance(Constructor.java:542) at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148) ... 108 more Caused by: java.lang.IncompatibleClassChangeError: org.apache.neethi.AssertionBuilderFactory at java.lang.ClassLoader.defineClassImpl(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:324) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:155) at com.ibm.ws.classloader.CompoundClassLoader._defineClass(CompoundClassLoader.java:857) at com.ibm.ws.classloader.CompoundClassLoader.localFindClass(CompoundClassLoader.java:765) at com.ibm.ws.classloader.CompoundClassLoader.loadClass(CompoundClassLoader.java:588) at java.lang.ClassLoader.loadClass(ClassLoader.java:731) at java.lang.ClassLoader.defineClassImpl(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:324) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:155) at com.ibm.ws.classloader.CompoundClassLoader._defineClass(CompoundClassLoader.java:857) at com.ibm.ws.classloader.CompoundClassLoader.localFindClass(CompoundClassLoader.java:765) at com.ibm.ws.classloader.CompoundClassLoader.loadClass(CompoundClassLoader.java:588) at java.lang.ClassLoader.loadClass(ClassLoader.java:731) at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:164) The solution here is quite simple: after searching through forums I found that WebSphere is also using Apache Neethi. Obviously of an older version. You got it right? I would expect that it keeps its stuff to itself, but it exposes these packages to it running applications. In short there are two options: either not use CXF and stick to the JEE API\u0026rsquo;s provided by the container, or go here:\nEnterprise Applications \u0026gt; your_ear_app \u0026gt; Class loader Class loader order -\u0026gt; Classes loaded with local class loader first (parent last) WAR class loader policy -\u0026gt; Single class loader for application and then here:\nEnterprise Applications \u0026gt; your_ear_app \u0026gt; Manage Modules \u0026gt; your_war_module Class loader order -\u0026gt; Classes loaded with local class loader first (parent last) Unfortunately these settings cannot be setup in a normal way via a descriptor or a manifest file in the application archive. Only manually with a mouse.\nAfter this step forward I got another error:\njava.lang.VerifyError: JVMVRFY013 class loading constraint violated; class=org/apache/cxf/jaxws/binding/soap/SOAPBindingImpl, method=getMessageFactory()Ljavax/xml/soap/Mes sageFactory;, pc=0 at java.lang.J9VMInternals.verifyImpl(Native Method) at java.lang.J9VMInternals.verify(J9VMInternals.java:94) at java.lang.J9VMInternals.initialize(J9VMInternals.java:169) at org.apache.cxf.jaxws.support.JaxWsEndpointImpl.createJaxwsBinding(JaxWsEndpointImpl.java:532) at org.apache.cxf.jaxws.support.JaxWsEndpointImpl.\u0026lt;init\u0026gt;(JaxWsEndpointImpl.java:157) at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.createEndpoint(JaxWsServiceFactoryBean.java:249) at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:173) at org.apache.cxf.frontend.ServerFactoryBean.create(ServerFactoryBean.java:159) at org.apache.cxf.jaxws.JaxWsServerFactoryBean.create(JaxWsServerFactoryBean.java:211) at org.apache.cxf.jaxws.EndpointImpl.getServer(EndpointImpl.java:456) at org.apache.cxf.jaxws.EndpointImpl.doPublish(EndpointImpl.java:334) at org.apache.cxf.jaxws.EndpointImpl.publish(EndpointImpl.java:251) at org.apache.cxf.jaxws.spi.ProviderImpl.createAndPublishEndpoint(ProviderImpl.java:155) at javax.xml.ws.Endpoint.publish(Endpoint.java:255) The solution here was not so straightforward. The general approach however is to: go to the source jar where the org.apache.cxf.jaxws.binding.soap.SOAPBindingImpl lies, look into which dependency is containing the javax.xml.soap.MessageFactory class; it is a SOAP API, which is included in the JDK 8, but you can also carry it around with you, if not sure you will be running in the Java 8 environment. In my case it was pulled in by the org.apache.servicemix.specs.saaj-api. The class is already loaded by the JVM bootloader and we are trying to load it from an external jar, application server VM thinks this is wrong. So we need to exclude the API from our war file:\n\u0026lt;build\u0026gt; \u0026lt;plugins\u0026gt; \u0026lt;plugin\u0026gt; \u0026lt;groupId\u0026gt;org.apache.maven.plugins\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;maven-war-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;packagingExcludes\u0026gt;WEB-INF/lib/org.apache.servicemix.specs.saaj-api*\u0026lt;/packagingExcludes\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;/plugins\u0026gt; \u0026lt;/build\u0026gt; Fortunately after removing this dependency I had no other issues and the application is running fine.\nGood luck searching your classpath.\nFirst published on the old anydoby.com blog on 2019-06-06.\n","date":"6 June 2019","externalUrl":null,"permalink":"/articles/how-to-run-your-cxf-application-in-websphere/","section":"Articles","summary":"","title":"How to run your CXF application in WebSphere","type":"articles"},{"content":"Recently I was building a little monolythic (yeah, it\u0026rsquo;s so nice to go back monolythic again) web app using Springboot and Polymer and got juite frustrated that our company\u0026rsquo;s Artifactory is protected even for readonly access and even for public repositories.\nNpm worked fine in our pre-configured Jenkins, because it had a /home/jenkins/.npmrc setup with authentication credentials (hashed of course). Unfortunately this hash does not quite work for Bower. It needs another hashed form (it\u0026rsquo;s some artifactory thing of course). Here\u0026rsquo;s the solution I found that works reasonably secure for Bower.\nIn your jenkinsfile you declare something like this before your stages:\nenvironment { BOWER_CREDS = credentials(\u0026#39;your-artifactory-credentials-id\u0026#39;) bower_registry = \u0026#34;https://${env.BOWER_CREDS_USR}:${env.BOWER_CREDS_PSW}@artifactory.mycompany.net/artifactory/api/bower/releases\u0026#34; } Of course someone (or you if you know the artifactory NPA user/password) has to create Jenkins credentials with the correct id.\nBower will pick up environment variable bower_registry and perform a login when necessary. The rest of bower properties you can commit to your git repository if needed in a .bowerrc file.\nStay safe.\nFirst published on the old anydoby.com blog on 2019-05-20.\n","date":"20 May 2019","externalUrl":null,"permalink":"/articles/configuring-bower-authentication-in-jenkins/","section":"Articles","summary":"","title":"Configuring Bower authentication in Jenkins","type":"articles"},{"content":"I\u0026rsquo;m often printing stuff for my kids, like old soviet \u0026ldquo;diafilms\u0026rdquo;. They turn into very nice colorful books where you have a lot of image and little text. Something suited for very small ones. It is quite straightforward to do this in Windows: just select images in Explorer and click Print. No linux file manager has this option out of the box, nor there exists an application that can easily allow you to print a book of images.\nSo I have to package all my JPG\u0026rsquo;s into a PDF and then you can print it from almost any viewer. Here\u0026rsquo;s my \u0026ldquo;application\u0026rdquo; for doing this (I put it to a local ~/bin/makebook):\n#!/bin/bash for i in *.jpg; do img2pdf ${i} \u0026gt; ${i}.pdf; done gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=book.pdf *.jpg.pdf rm *.jpg.pdf so, the first line is converting all my JPG\u0026rsquo;s to individual PDF\u0026rsquo;s without losing quality. Unfortunately the img2pdf cannot merge multiple PDF\u0026rsquo;s. The second line \u0026ldquo;prints\u0026rdquo; all these files using a virtual printer. The result is a nice book.pdf full of pictures.\nFirst published on the old anydoby.com blog on 2019-05-01.\n","date":"1 May 2019","externalUrl":null,"permalink":"/articles/how-to-convert-jpg-s-to-a-single-pdf-in-linux-without-losing/","section":"Articles","summary":"","title":"How to convert JPG's to a single PDF in Linux without losing quality","type":"articles"},{"content":"","date":"1 May 2019","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"Recently I\u0026rsquo;ve stepped away from the shiny linux desktop environments into a geeky openbox. Black screen and mouse pointer. Nothing that distracts you from work. Trying to do as much as possible from the term as well. This goes for volume controls as well. I\u0026rsquo;ve discovered a lot of details about sound and mixing :) It appears volume is relative, especially if you have a lot of sources and sinks. Such simple thing as volume that\u0026rsquo;s presented by a desktop environment is exposed to you in the form of sinks and inputs outputs by pulseaudio. So I had to study the subject a bit and with some trial and error found the sweet spot in taming all the seakers/headphones/bluetooth:\n\u0026lt;keybind key=\u0026#34;XF86AudioMute\u0026#34;\u0026gt; \u0026lt;action name=\u0026#34;Execute\u0026#34;\u0026gt; \u0026lt;command\u0026gt;sh -c \u0026#34;pactl list sinks | grep \u0026#39;Sink #\u0026#39; | cut -d\u0026#39;#\u0026#39; -f2 | xargs -I@ pactl -- set-sink-mute @ toggle\u0026#34;\u0026lt;/command\u0026gt; \u0026lt;/action\u0026gt; \u0026lt;/keybind\u0026gt; \u0026lt;keybind key=\u0026#34;XF86AudioLowerVolume\u0026#34;\u0026gt; \u0026lt;action name=\u0026#34;Execute\u0026#34;\u0026gt; \u0026lt;command\u0026gt;sh -c \u0026#34;pactl list sinks | grep \u0026#39;Sink #\u0026#39; | cut -d\u0026#39;#\u0026#39; -f2 | xargs -I@ pactl -- set-sink-volume @ -2000\u0026#34;\u0026lt;/command\u0026gt; \u0026lt;/action\u0026gt; \u0026lt;/keybind\u0026gt; \u0026lt;keybind key=\u0026#34;XF86AudioRaiseVolume\u0026#34;\u0026gt; \u0026lt;action name=\u0026#34;Execute\u0026#34;\u0026gt; \u0026lt;command\u0026gt;sh -c \u0026#34;pactl list sinks | grep \u0026#39;Sink #\u0026#39; | cut -d\u0026#39;#\u0026#39; -f2 | xargs -I@ pactl -- set-sink-volume @ +2000\u0026#34;\u0026lt;/command\u0026gt; \u0026lt;/action\u0026gt; \u0026lt;/keybind\u0026gt; So far I\u0026rsquo;m using only one player for terminal, but in the future I plan to add play/pause next/prev shortcuts for YoutubeMusic (its the one that sits in your browser, aha).\n\u0026lt;keybind key=\u0026#34;XF86AudioPlay\u0026#34;\u0026gt; \u0026lt;action name=\u0026#34;Execute\u0026#34;\u0026gt; \u0026lt;command\u0026gt;mocp --toggle-pause\u0026lt;/command\u0026gt; \u0026lt;/action\u0026gt; \u0026lt;/keybind\u0026gt; \u0026lt;keybind key=\u0026#34;XF86AudioNext\u0026#34;\u0026gt; \u0026lt;action name=\u0026#34;Execute\u0026#34;\u0026gt; \u0026lt;command\u0026gt;mocp --next\u0026lt;/command\u0026gt; \u0026lt;/action\u0026gt; \u0026lt;/keybind\u0026gt; \u0026lt;keybind key=\u0026#34;XF86AudioPrev\u0026#34;\u0026gt; \u0026lt;action name=\u0026#34;Execute\u0026#34;\u0026gt; \u0026lt;command\u0026gt;mocp --previous\u0026lt;/command\u0026gt; \u0026lt;/action\u0026gt; \u0026lt;/keybind\u0026gt; First published on the old anydoby.com blog on 2019-04-21.\n","date":"21 April 2019","externalUrl":null,"permalink":"/articles/adjusting-volume-using-mediakeys-in-openbox/","section":"Articles","summary":"","title":"Adjusting volume using mediakeys in openbox","type":"articles"},{"content":"","date":"21 April 2019","externalUrl":null,"permalink":"/tags/openbox/","section":"Tags","summary":"","title":"Openbox","type":"tags"},{"content":"Why do it?\nThe thing is that my VPS which I used for the last 8 years started costing me 60 USD instead of 20 per month. Too much for a homepage I said and turned off my website. For a month. In this month I bought myself a toy Raspberry Pi 3 tuned everything so that it could run a Java servlet container (they are still popular these days, yeah).\nI chose Ubuntu 2015 server minimal as my server OS (only 35mb RAM when installed on Raspberry, so you have plenty for Java). Frankly speaking I\u0026rsquo;d like to install Gentoo. But alas, Gentoo is not yet fully supporting the armv8 officially. So we take Ubuntu. Turn off root and password based access, ssh-copy-id and work safely, it\u0026rsquo;s a server after all.\nEven after fresh install you will have some outdated packages so it\u0026rsquo;s better to do this before we start:\napt-get update apt-get dist-upgrade After connecting to your router via Ethernet we can ssh to it.\nI don\u0026rsquo;t like installing java through the package management, since I rarely see added value in it. You\u0026rsquo;ll have to do manual steps anyway to install Oracle JDK, so let\u0026rsquo;s go manual. Install Java, first download it from Oracle, untar to usr/lib/jvm and declare JAVA_HOME in the /etc/environment, like this:\nJAVA_HOME=/usr/lib/jvm/jdk1.8.0_91 PATH=\u0026#34;/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$JAVA_HOME/bin\u0026#34; The add the following to the ~/.bash_profile\nsource /etc/environment and relogin.\nNext install Tomcat. Package management again is not our choice here. So we just download it from Apache. Currently this site uses 8, but you are free to install something fresher. Unpack it somewhere to /opt/tomcat.\nAdd the tomcat user and give it cat rights:\ngroupadd tomcat useradd -s /bin/false -g tomcat -d /opt/tomcat tomcat chown -R tomcat:tomcat /opt/tomcat In order to be able to run tomcat as a service as system boot we\u0026rsquo;ll create a service declaration /etc/systemd/system/tomcat.service\n# Systemd unit file for tomcat [Unit] Description=Apache Tomcat Web Application Container After=syslog.target network.target [Service] Type=forking EnvironmentFile=/etc/environment # you can explicitly set the JAVA_HOME #Environment=JAVA_HOME=/usr/lib/jvm/jre Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid Environment=CATALINA_HOME=/opt/tomcat Environment=CATALINA_BASE=/opt/tomcat # we tell it we want the server VM Environment=\u0026#39;CATALINA_OPTS=-Xms256M -Xmx512M -server -XX:+UseParallelGC\u0026#39; Environment=\u0026#39;JAVA_OPTS=-Djava.awt.headless=true -Djava.net.preferIPv4Stack=true\u0026#39; ExecStart=/opt/tomcat/bin/startup.sh ExecStop=/bin/kill -15 $MAINPID User=tomcat Group=tomcat [Install] WantedBy=multi-user.target Basic system is able to start now:\nsystemctl daemon-reload systemctl enable tomcat systemctl start tomcat tail -f /opt/tomcat/logs/catalina.out Watch the logs roll. Still not impressive: it\u0026rsquo;s running on port 8080, and we want the 80. Tomcat won\u0026rsquo;t bind the protected port 80, so we can either open a security hole and give it root access or use something more neat like this:\napt-get install authbind touch /etc/authbind/byport/80 chmod 500 /etc/authbind/byport/80 chown tomcat /etc/authbind/byport/80 If you further need SSL (I did need it), then you create a file for 443. Next we\u0026rsquo;ll have to modify the /opt/tomcat/bin/startup.sh, search and replace the following launch command:\n#exec \u0026#34;$PRGDIR\u0026#34;/\u0026#34;$EXECUTABLE\u0026#34; start \u0026#34;$@\u0026#34; exec authbind --deep \u0026#34;$PRGDIR\u0026#34;/\u0026#34;$EXECUTABLE\u0026#34; start \u0026#34;$@\u0026#34; Change ports in the /opt/tomcat/conf/server.xml:\n\u0026lt;Connector port=\u0026#34;80\u0026#34; protocol=\u0026#34;HTTP/1.1\u0026#34; connectionTimeout=\u0026#34;20000\u0026#34; maxThreads=\u0026#34;20\u0026#34; redirectPort=\u0026#34;443\u0026#34; address=\u0026#34;192.168.1.50\u0026#34; URIEncoding=\u0026#34;utf-8\u0026#34; useBodyEncodingForURI=\u0026#34;true\u0026#34;/\u0026gt; In the address attribute we\u0026rsquo;ll have to specify the IP of the machine. I used to have an externally routable VPS IP and put it here. Now I run behind the home router NAT and have to humbly use this one (if you are not on eth0, then modify the command):\nifconfig eth0 | grep -oE \u0026#39;(([0-9]){1,3}\\.){3}[0-9]{1,3}\u0026#39; | head -1 Save and restart tomcat:\nsystemctl restart tomcat tail -f /opt/tomcat/logs/catalina.out If you see something like the following in the log, then everything went fine:\norg.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler [\u0026#34;http-nio-192.168.1.56-80\u0026#34;] We could stop right here but we\u0026rsquo;d also like our server to not hickup when servicing simple static resources, like Apache does. So we need to setup Tomcat APR - it\u0026rsquo;s a native protocol which uses Apache Portable Runtime for serving static content using the OS primitives not burdening the JVM. They say it works better.\napt-get install libapr1-dev apt-get install libssl-dev cd /opt/tomcat/bin tar -xpf tomcat-native.tar.gz cd tomcat-native-*src/native ./configure \u0026amp;\u0026amp; make \u0026amp;\u0026amp; make install If for some reason you see something like this in the make output\n/usr/lib/jvm/jdk1.8.0_91/include/jni.h:45:20: fatal error: jni_md.h: No such file or directory you can create a symlink and repeat:\nln -s /usr/lib/jvm/jdk1.8.0_91/include/linux /usr/lib/jvm/jdk1.8.0_91/include/arm APR is installed in the /usr/local/apr/lib. In order for tomcat to detect it we\u0026rsquo;ll have to modify the /etc/systemd/system/tomcat.service\nEnvironment=\u0026#39;JAVA_OPTS=-Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Djava.library.path=/usr/local/apr/lib\u0026#39; Reload daemons and restart tomcat. Now the log will contain the following output:\nINFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [\u0026#34;http-apr-192.168.1.56-80\u0026#34;] This means we have successfully detected APR libraries and created another connector type. If your application uses a catch-all spring dispatcher servlet like below:\n\u0026lt;servlet\u0026gt; \u0026lt;servlet-name\u0026gt;dispatcher\u0026lt;/servlet-name\u0026gt; \u0026lt;servlet-class\u0026gt;org.springframework.web.servlet.DispatcherServlet\u0026lt;/servlet-class\u0026gt; \u0026lt;load-on-startup\u0026gt;1\u0026lt;/load-on-startup\u0026gt; \u0026lt;/servlet\u0026gt; \u0026lt;servlet-mapping\u0026gt; \u0026lt;servlet-name\u0026gt;dispatcher\u0026lt;/servlet-name\u0026gt; \u0026lt;url-pattern\u0026gt;/\u0026lt;/url-pattern\u0026gt; \u0026lt;/servlet-mapping\u0026gt; then you\u0026rsquo;ll need to tell tomcat to server statics differently:\n\u0026lt;servlet-mapping\u0026gt; \u0026lt;servlet-name\u0026gt;default\u0026lt;/servlet-name\u0026gt; \u0026lt;url-pattern\u0026gt;*.zip\u0026lt;/url-pattern\u0026gt; \u0026lt;url-pattern\u0026gt;*.jpg\u0026lt;/url-pattern\u0026gt; \u0026lt;url-pattern\u0026gt;*.png\u0026lt;/url-pattern\u0026gt; \u0026lt;url-pattern\u0026gt;*.css\u0026lt;/url-pattern\u0026gt; \u0026lt;url-pattern\u0026gt;*.js\u0026lt;/url-pattern\u0026gt; \u0026lt;url-pattern\u0026gt;*.pdf\u0026lt;/url-pattern\u0026gt; \u0026lt;url-pattern\u0026gt;*.mp3\u0026lt;/url-pattern\u0026gt; \u0026lt;url-pattern\u0026gt;*.gif\u0026lt;/url-pattern\u0026gt; \u0026lt;url-pattern\u0026gt;*.rar\u0026lt;/url-pattern\u0026gt; \u0026lt;url-pattern\u0026gt;*.bmp\u0026lt;/url-pattern\u0026gt; \u0026lt;url-pattern\u0026gt;*.exe\u0026lt;/url-pattern\u0026gt; \u0026lt;/servlet-mapping\u0026gt; default is a standard tomcat servlet which services static requests among the others. You do not have to declare the servlet in your web.xml, tomcat already knows about it.\nSo how do we secure it all? If you simply want to SSL all the resources then just these lines in the web.xml will be enough\n\u0026lt;security-constraint\u0026gt; \u0026lt;web-resource-collection\u0026gt; \u0026lt;web-resource-name\u0026gt;all\u0026lt;/web-resource-name\u0026gt; \u0026lt;url-pattern\u0026gt;/*\u0026lt;/url-pattern\u0026gt; \u0026lt;/web-resource-collection\u0026gt; \u0026lt;user-data-constraint\u0026gt; \u0026lt;description\u0026gt;all traffic will go through ssl\u0026lt;/description\u0026gt; \u0026lt;transport-guarantee\u0026gt;CONFIDENTIAL\u0026lt;/transport-guarantee\u0026gt; \u0026lt;/user-data-constraint\u0026gt; \u0026lt;/security-constraint\u0026gt; All HTTP traffic will be redirected to HTTPS. We only need to setup SSL within tomcat now. If you chose the no-APR way then you simply have to create a certificate store and tell tomcat about its location:\nkeytool -genkey -keysize 2048 -keyalg RSA -alias tomcat -keystore mystore.jks It is important that you use the same password for tomcat alias and for the keystore itself (it is a well known bug).\nNow you need to tell about the key in the /opt/tomcat/conf/server.xml\n\u0026lt;Connector port=\u0026#34;443\u0026#34; protocol=\u0026#34;org.apache.coyote.http11.Http11Nio2Protocol\u0026#34; address=\u0026#34;192.168.1.56\u0026#34; maxThreads=\u0026#34;20\u0026#34; SSLEnabled=\u0026#34;true\u0026#34; scheme=\u0026#34;https\u0026#34; secure=\u0026#34;true\u0026#34; keystoreFile=\u0026#34;${catalina.base}/conf/ssl/mystore.jks\u0026#34; keystorePass=\u0026#34;mypass\u0026#34; clientAuth=\u0026#34;false\u0026#34; sslProtocol=\u0026#34;TLS\u0026#34; URIEncoding=\u0026#34;utf-8\u0026#34; useBodyEncodingForURI=\u0026#34;true\u0026#34;/\u0026gt; If you however chose the native way (like me, with APR which uses OpenSSL), then you\u0026rsquo;ll either have to generate the keys using OpenSSL or convert your jks keystore into the PKCS12 format. This is simple:\nkeytool -importkeystore -srckeystore mystore.jks -destkeystore mystore.p12 -deststoretype PKCS12 -srcalias tomcat -srcstorepass mypass -deststorepass mypass -destkeypass mypass You\u0026rsquo;ll get the file mystore.p12 in the format which is readily understood by OpenSSL. Now what is left is to extract private/public key and certificate authority chain from it:\nopenssl pkcs12 -in mystore.p12 -nocerts -out my.key.pem openssl pkcs12 -in mystore.p12 -clcerts -out my.cert.pem openssl pkcs12 -in mystore.p12 -cacerts -out my.chain.pem If you don\u0026rsquo;t want the browser scoff at your certificates it is advisable to pay some moderate amount of money to sign it by higher leverl authority, at least here.\nNow we\u0026rsquo;ll need to configure SSL and APR in the server.xml:\n\u0026lt;Connector port=\u0026#34;443\u0026#34; maxHttpHeaderSize=\u0026#34;8192\u0026#34; address=\u0026#34;192.168.1.56\u0026#34; maxThreads=\u0026#34;20\u0026#34; enableLookups=\u0026#34;false\u0026#34; disableUploadTimeout=\u0026#34;true\u0026#34; acceptCount=\u0026#34;100\u0026#34; scheme=\u0026#34;https\u0026#34; secure=\u0026#34;true\u0026#34; SSLEnabled=\u0026#34;true\u0026#34; SSLCertificateFile=\u0026#34;${catalina.base}/conf/ssl/my.cert.pem\u0026#34; SSLCertificateKeyFile=\u0026#34;${catalina.base}/conf/ssl/my.key.pem\u0026#34; SSLCertificateChainFile=\u0026#34;${catalina.base}/conf/ssl/my.chain.pem\u0026#34; SSLPassword=\u0026#34;mypass\u0026#34; URIEncoding=\u0026#34;utf-8\u0026#34; useBodyEncodingForURI=\u0026#34;true\u0026#34;/\u0026gt; After tomcat restart you can see from the logs that port 443 is also serviced by the APR connector.\nThat\u0026rsquo;s it. No, not yet. Don\u0026rsquo;t forget to let the world know about your little Pi by forwarding ports 80 and 443 on your router to the internal IP of your server.\nFirst published on the old anydoby.com blog on 2016-04-30.\n","date":"30 April 2016","externalUrl":null,"permalink":"/articles/cheap-java-tomcat-server-with-raspberrypi3/","section":"Articles","summary":"","title":"Cheap Java/Tomcat server with RaspberryPi3","type":"articles"},{"content":"An attempt to install Oracle JDK in Gentoo leads to mandatory installation of a ice tea cup (icedtea-bin +90mb of redundant binaries). This sort of contradicts the concept of a lightweight distro, right?\nI suspect that this is just a dependency bug since icedtea is mandatory for the java-config (which manages which java is active on your system). And you cannot go without it. Almost. Having googled a bit I found a nice solution:\n# pull in the config package without dependencies emerge -1 --nodeps app-admin/eselect-java # next goes the thing that pulls the package emerge -av --tree oracle-jdk-bin:1.8 It will swear you have to accept some licenses, download stuff manually etc, do what it asks. JDK and JCE policy (if you need it), download manually and put to /usr/portage/distfiles.\nLicences I accept manually, who reads them anyway?\necho \u0026#39;ACCEPT_LICENSE=\u0026#34;*\u0026#34;\u0026#39; \u0026gt;\u0026gt; /etc/portage/make.conf echo \u0026#34;=dev-java/oracle-jdk-bin-1.8.0.25 ~amd64\u0026#34; \u0026gt;\u0026gt; /etc/portage/package.accept_keywords If the installer complains that it cannot unpack the tars, do not forget to let portage access the files:\nchown -R portage:portage /usr/portage/distfiles/jce_policy-8.zip chown -R portage:portage /usr/portage/distfiles/jdk-8u25-linux-x64.tar.gz Now let\u0026rsquo;s check whether we have it installed:\neselect java-vm list Available Java Virtual Machines: [1] oracle-jdk-bin-1.8 system-vm That\u0026rsquo;s it.\nWell, not quite :) If you later try to emerge @world the package eselect-java will definitely try to restore justice by sucking in the icedtea to satisfy its dependencies. In order to overcome this let\u0026rsquo;s change some files.\nMask icedtea\n# /etc/portage/package.mask dev-java/icedtea-bin dev-java/icedtea-web Change the versions of virtual packages accepted from 1.6 to 1.8 (these are not stable package as of time of this writing):\n# /etc/portage/package.unmask \u0026gt;=virtual/jdk-1.8 \u0026gt;=virtual/jre-1.8 And finally we need to accept new keywords (for my system its ~amd64):\n# /etc/portage/package.accept_keywords \u0026gt;=virtual/jdk-1.8.0 ~amd64 \u0026gt;=virtual/jre-1.8.0 ~amd64 Now that\u0026rsquo;s it.\nFirst published on the old anydoby.com blog on 2014-12-31.\n","date":"31 December 2014","externalUrl":null,"permalink":"/articles/installing-oracle-jdk-8-in-gentoo-without-icedtea/","section":"Articles","summary":"","title":"Installing Oracle JDK 8 in Gentoo without icedtea","type":"articles"},{"content":"A very short notice. If you have a really huge resultset that you only need to traverse once in one direction never use ResultSet.TYPE_SCROLL_INSENSITIVE or ResultSet.TYPE_SCROLL_SENSITIVE, in Oracle. Only the ResultSet.TYPE_FORWARD_ONLY.\nToday I worked on one of our numerous OutOfMemory problems that had to do with a large resultset. Oracle driver appears to be caching the CachedRowElement\u0026rsquo;s in memory!!!\nFirst published on the old anydoby.com blog on 2011-03-23.\n","date":"23 March 2011","externalUrl":null,"permalink":"/articles/oom-in-oracle/","section":"Articles","summary":"","title":"OOM in Oracle","type":"articles"},{"content":"Those who have to process scans should know how painful it is to manually deskew images. There are several approaches to do this deskewing automatically. The basis of all the methods is to identify lines following the same direction in a image and then by deviation from horizontal or vertical axis we can guess the skew angle. Then we choose the best lines and deskew the image.\nI have used the Hough transform, which has a plenty of examples on the net and produces soso results. But only for the images without lineart that contains weird lines (it treats them as main lines :)). My task was exactly the opposite - to deskew images with lineart on them.\nAfter thorough search I found an interesting abandoned Gimp autodeskew plugin - it uses GPL version of the Radon transform, a much more sophisticated technique used in x-ray analysis. This very transform finds scew so nicely that I decided to port it into Java and use in my project. The source code for C++ is here. It is so convoluted that translating it and making it work in Java took about 2 days. Here\u0026rsquo;s what I came up with:\npublic double doIt(BufferedImage image) { final double skewRadians; BufferedImage black = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_BINARY); final Graphics2D g = black.createGraphics(); g.drawImage(image, 0, 0, null); g.dispose(); skewRadians = findSkew(black); System.out.println(-57.295779513082320876798154814105 * skewRadians); return skewRadians; } static int getByteWidth(final int width) { return (width + 7) / 8; } static int next_pow2(final int n) { int retval = 1; while (retval \u0026lt; n) { retval \u0026lt;\u0026lt;= 1; } return retval; } static class BitUtils { static int[] bitcount_ = new int[256]; static int[] invbits_ = new int[256]; static { for (int i = 0; i \u0026lt; 256; i++) { int j = i, cnt = 0; do { cnt += j \u0026amp; 1; } while ((j \u0026gt;\u0026gt;= 1) != 0); int x = (i \u0026lt;\u0026lt; 4) | (i \u0026gt;\u0026gt; 4); x = ((x \u0026amp; 0xCC) \u0026gt;\u0026gt; 2) | ((x \u0026amp; 0x33) \u0026lt;\u0026lt; 2); x = ((x \u0026amp; 0xAA) \u0026gt;\u0026gt; 1) | ((x \u0026amp; 0x55) \u0026lt;\u0026lt; 1); bitcount_[i] = cnt; invbits_[i] = x; } } } static double findSkew(final BufferedImage img) { final DataBuffer buffer = img.getRaster().getDataBuffer(); final int byteWidth = getByteWidth(img.getWidth()); final int padmask = 0xFF \u0026lt;\u0026lt; ((img.getWidth() + 7) % 8); int elementIndex = 0; for (int row = 0; row \u0026lt; img.getHeight(); row++) { for (int col = 0; col \u0026lt; byteWidth; col++) { int elem = buffer.getElem(elementIndex); elem ^= 0xff;// invert colors elem = BitUtils.invbits_[elem]; // Change the bit order buffer.setElem(elementIndex, elem); elementIndex++; } final int lastElement = buffer.getElem(elementIndex - 1) \u0026amp; padmask; buffer.setElem(elementIndex - 1, lastElement); // Zero trailing bits } final int w2 = next_pow2(byteWidth); final int ssize = 2 * w2 - 1; // Size of sharpness table final int sharpness[] = new int[ssize]; radon(img.getWidth(), img.getHeight(), buffer, 1, sharpness); radon(img.getWidth(), img.getHeight(), buffer, -1, sharpness); int i, imax = 0; int vmax = 0; double sum = 0.; for (i = 0; i \u0026lt; ssize; i++) { final int s = sharpness[i]; if (s \u0026gt; vmax) { imax = i; vmax = s; } sum += s; } final int h = img.getHeight(); if (vmax \u0026lt;= 3 * sum / h) { // Heuristics !!! return 0; } final double iskew = imax - w2 + 1; return Math.atan(iskew / (8 * w2)); } static void radon(final int width, final int height, final DataBuffer buffer, final int sign, final int sharpness[]) { int[] p1_, p2_; // Stored columnwise final int w2 = next_pow2(getByteWidth(width)); final int w = getByteWidth(width); final int h = height; final int s = h * w2; p1_ = new int[s]; p2_ = new int[s]; // Fill in the first table int row, column; int scanlinePosition = 0; for (row = 0; row \u0026lt; h; row++) { scanlinePosition = row * w; for (column = 0; column \u0026lt; w; column++) { if (sign \u0026gt; 0) { final int b = buffer.getElem(0, scanlinePosition + w - 1 - column); p1_[h * column + row] = BitUtils.bitcount_[b]; } else { final int b = buffer.getElem(0, scanlinePosition + column); p1_[h * column + row] = BitUtils.bitcount_[b]; } } } int[] x1 = p1_; int[] x2 = p2_; // Iterate int step = 1; for (;;) { int i; for (i = 0; i \u0026lt; w2; i += 2 * step) { int j; for (j = 0; j \u0026lt; step; j++) { // Columns-sources: final int s1 = h * (i + j);// x1 pointer final int s2 = h * (i + j + step); // x1 pointer // Columns-targets: final int t1 = h * (i + 2 * j); // x2 pointer final int t2 = h * (i + 2 * j + 1); // x2 pointer int m; for (m = 0; m \u0026lt; h; m++) { x2[t1 + m] = x1[s1 + m]; x2[t2 + m] = x1[s1 + m]; if (m + j \u0026lt; h) { x2[t1 + m] += x1[s2 + m + j]; } if (m + j + 1 \u0026lt; h) { x2[t2 + m] += x1[s2 + m + j + 1]; } } } } // Swap the tables: final int[] aux = x1; x1 = x2; x2 = aux; // Increase the step: step *= 2; if (step \u0026gt;= w2) { break; } } // Now, compute the sum of squared finite differences: for (column = 0; column \u0026lt; w2; column++) { int acc = 0; final int col = h * column; for (row = 0; row + 1 \u0026lt; h; row++) { final int diff = x1[col + row] - x1[col + row + 1]; acc += diff * diff; } sharpness[w2 - 1 + sign * column] = acc; } } This algorythm is damn fast because it calculates 8 pixels at a time - operating on a byte bitmap with precalculated stuff for all pixel permutations in a byte. Don\u0026rsquo;t ask me how it does the job, it just does it :) Enjoy.\nFirst published on the old anydoby.com blog on 2010-10-27.\n","date":"27 October 2010","externalUrl":null,"permalink":"/articles/automatic-image-deskew-in-java/","section":"Articles","summary":"","title":"Automatic image deskew in Java","type":"articles"},{"content":"","date":"27 October 2010","externalUrl":null,"permalink":"/tags/graphics/","section":"Tags","summary":"","title":"Graphics","type":"tags"},{"content":"","date":"6 October 2010","externalUrl":null,"permalink":"/tags/camel/","section":"Tags","summary":"","title":"Camel","type":"tags"},{"content":"Camel 2.4.0 introduced a nice feature which broke Quartz routes in our project:\nIntroduced StartupListener to allow components/endpoints/producers/consumers etc. as a listener to be notified when CamelContext have just been started. This allows any custom logic to be executed as a late starter. This ensures Quartz scheduler is only started when all the routes and so forth is started and running. The problem is - if you have no routes in camel context at startup you will never see Quartz working, because QuartzComponent.startScheduler is invoked after all subscriptions were added and the context had been started. The startScheduler checks whether private static Scheduler instance is null and if so exits. The tricky thing is, the scheduler field is populated only when the component is started in the doStart method. But it\u0026rsquo;s a bit too late. The scheduler is there and there is noone to start it, hence the dead Quartz routes.\nI made a simple fix for those who really need to dynamically populate camel routes after the context was started, here it is:\n\u0026lt;camel:camelContext id=\u0026#34;camelContext\u0026#34; handleFault=\u0026#34;true\u0026#34; streamCache=\u0026#34;false\u0026#34; trace=\u0026#34;true\u0026#34; autoStartup=\u0026#34;true\u0026#34;\u0026gt; \u0026lt;camel:route\u0026gt; \u0026lt;camel:from uri=\u0026#34;quartz://dummy/dummytrigger?fireNow=true\u0026#34;/\u0026gt; \u0026lt;camel:to uri=\u0026#34;mock:something\u0026#34;/\u0026gt; \u0026lt;/camel:route\u0026gt; \u0026lt;/camel:camelContext\u0026gt; This way QuartzComponent gets a functional and started scheduler for all new routes that you add later.\nHope Claus will figure out from this a possible graceful fix :)\nHere (not archived) is a project which reproduces the thing.\nFirst published on the old anydoby.com blog on 2010-10-06.\n","date":"6 October 2010","externalUrl":null,"permalink":"/articles/new-and-noteworthy/","section":"Articles","summary":"","title":"New and noteworthy","type":"articles"},{"content":"Wrote a very handy thing which may prove useful to everybody using Spring. It helps treat properties from a property file or system properties as beans of corresponding type (conversion for String, Integer and Boolean is built-in). Bean ids are the same as property names in property file. This is very different from what a default org.springframework.beans.factory.config.PropertyPlaceholderConfigurer, offers, which just fills bean properties with values once.\nI also added a simple way to fill in the placeholders in property values themselves. Have a look at unit tests to see how to do this.\nHere is the code:\npackage com.anydoby.spring; import java.io.IOException; import java.util.Properties; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.util.StringUtils; /** * PropertyPlaceholderConfigurer for reusable properties. Normally, you cannot * retrieve the properties from the PropertyPlaceholderConfigurer but this * version has a getProperties() method to do just that. */ public class ReusablePropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer implements ApplicationContextAware { private Properties properties; private final static Pattern HOLDER_PATTERN = Pattern.compile(\u0026#34;[$][{]([^}]*)[}]\u0026#34;); private static final Pattern INTEGER_PATTERN = Pattern.compile(\u0026#34;\\\\d{1,\u0026#34; + Integer.toString(Integer.MAX_VALUE).length() + \u0026#34;}\u0026#34;); private Properties commandLineArgs = new Properties(); private BeanDefinitionRegistry registry; /** * @return the \u0026lt;code\u0026gt;commandLineArgs\u0026lt;/code\u0026gt; property */ public final Properties getCommandLineArgs() { return this.commandLineArgs; } /** * @param commandLineArgs * the commandLineArgs to set the property to */ public final void setCommandLineArgs(final Properties commandLineArgs) { this.commandLineArgs = commandLineArgs; } /** * Delegates the loading to the standard {@link PropertyPlaceholderConfigurer} * but also saves the properties so we can reuse them. The saved properties are * processed to resolve references to other properties. * * @param properties * to load */ @Override public void loadProperties(final Properties properties) throws IOException { if (this.commandLineArgs != null) { properties.putAll(this.commandLineArgs); } this.properties = new Properties(); super.loadProperties(properties); for (final Entry\u0026lt;Object, Object\u0026gt; entry : properties.entrySet()) { if (!this.properties.containsKey(entry.getKey())) { this.properties.put(entry.getKey(), entry.getValue()); } } for (final Entry\u0026lt;Object, Object\u0026gt; entry : this.properties.entrySet()) { final String newValue = resolveValueProperties(this.properties, (String) entry.getValue()); this.properties.put(entry.getKey(), newValue); } if (this.registry != null) { for (final Entry\u0026lt;Object, Object\u0026gt; entry : this.properties.entrySet()) { final Object key = entry.getKey(); final String beanName = key.toString(); final Object value = entry.getValue(); final String stringValue = value.toString(); final BeanDefinitionBuilder beanDefinitionBuilder; if (isBoolean(stringValue)) { beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Boolean.class); } else if (isInteger(stringValue)) { beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Integer.class); } else { beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(String.class); } beanDefinitionBuilder.addConstructorArgValue(stringValue); beanDefinitionBuilder.setScope(BeanDefinition.SCOPE_SINGLETON); final AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition(); final BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, beanName); this.logger.debug(\u0026#34;Registering \u0026#34; + beanName + \u0026#34; with value \u0026#34; + stringValue + \u0026#34; as \u0026#34; + beanDefinition.getBeanClassName()); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); } } } private boolean isInteger(final String stringValue) { return INTEGER_PATTERN.matcher(stringValue).matches(); } private boolean isBoolean(final String stringValue) { return Boolean.TRUE.toString().equals(stringValue) || Boolean.FALSE.toString().equals(stringValue); } /** * Returns all properties that have been loaded. * * @return loaded properties */ public Properties getProperties() { return this.properties; } /** * Resolve the references to properties in the specified value. * \u0026lt;p/\u0026gt; * Example: value = \u0026#34;${foo} ${bar}\u0026#34; and properties containing a value \u0026#34;Hello\u0026#34; * for key \u0026#34;foo\u0026#34; and containing a value \u0026#34;world\u0026#34; for key \u0026#34;bar\u0026#34; will result in * \u0026#34;Hello world\u0026#34;. * * @param properties * the properties to look up values. * @param value * the value to resolve. Possibly containing references. * @return the resolved value. */ public static String resolveValueProperties(final Properties properties, final String value) { final Matcher matcher = HOLDER_PATTERN.matcher(value); final StringBuffer sb = new StringBuffer(); while (matcher.find()) { final String holder = matcher.group(0); final String holderName = matcher.group(1); final String replacement; if (!StringUtils.hasText(holderName)) { final String property = properties.getProperty(holderName); if (property != null) { replacement = property; } else if (System.getProperty(holderName) != null) { replacement = System.getProperty(holderName); } else { replacement = holder; } } else { replacement = holder; } matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement)); } matcher.appendTail(sb); return sb.toString(); } @Override public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { findRegistry(applicationContext); } private void findRegistry(final ApplicationContext applicationContext) { if (applicationContext == null) { this.logger.warn(\u0026#34;Unable to find an application context which provides BeanDefinitionRegistry functionality. \u0026#34; + \u0026#34;Properties will not be exposed as beans.\u0026#34;); return; } final AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory(); if (beanFactory instanceof BeanDefinitionRegistry) { this.registry = (BeanDefinitionRegistry) beanFactory; } else { findRegistry(applicationContext.getParent()); } } } And here you can have a look (not archived) at how to use this in action. Look into the unit test com.anydoby.spring.TestOptionalProperty.\nFirst published on the old anydoby.com blog on 2010-07-20.\n","date":"20 July 2010","externalUrl":null,"permalink":"/articles/reusable-properties-exposed-as-beans-in-spring/","section":"Articles","summary":"","title":"Reusable properties exposed as beans in Spring","type":"articles"},{"content":"Try this simple example:\npublic class Main { public static class Item {} public static void main(String[] args) { Item myItem = new Item(); // enter \u0026#34;add\u0026#34; and ctrl+space } private static void add(Item item) { } } If you do it in clean installation of Eclipse the add(myItem) will be added, which I expect. After you install AJDT it will be add(item) - just the name of method argument. Stupid and annoying. It trippled the effort on coding - first you have to enter obvious arguments yourself and moreover you have to correct the meaningless \u0026ldquo;best guesses\u0026rdquo; in case you do not have a source for the library you are calling. In this case argument names will be\u0026hellip; you guessed it - arg0, arg1, etc.\nAfter installing AJDT you will never get reasonable autocompletion for method and constructor parameters. Luckily I\u0026rsquo;ve found a simple solution - go to Window/Properties/JDT Weaving and turn it off. Then all of a sudden autocompletion is back again :) It seems that weaving features of AJDT are not affected by this button.\nPS: Corresponding bug was recorded. Waiting for the fix.\nPPS: Wow, they fixed it the day I reported the bug :)\nFirst published on the old anydoby.com blog on 2009-06-30.\n","date":"30 June 2009","externalUrl":null,"permalink":"/articles/eclipse-autocompletion-is-dead/","section":"Articles","summary":"","title":"Eclipse autocompletion is dead","type":"articles"},{"content":"Today I stumbled upon a funny null issue with Derby and iBATIS:\njava.sql.SQLDataException: An attempt was made to get a data value of type \u0026#39;\u0026lt;UNKNOWN\u0026gt;\u0026#39; from a data value of type CHAR It happened when I tried to perform an iBATIS update and a string value of my POJO was null. The problem appeared to be trivial: I used parameterClass in update and iBATIS, naturally, did not know any good way of telling Derby what type of null to use :) (and Derby was dumb enough not to set a value to null anyway)\nThe solution is simple: use parameterMap for updates and in the map clearly specify the jdbcType for all attributes which can become nulls. Like this, for example:\n\u0026lt;parameterMap class=\u0026#34;user\u0026#34; id=\u0026#34;userMap\u0026#34;\u0026gt; \u0026lt;parameter property=\u0026#34;username\u0026#34; jdbcType=\u0026#34;VARCHAR\u0026#34;/\u0026gt; \u0026lt;parameter property=\u0026#34;password\u0026#34; jdbcType=\u0026#34;CHAR\u0026#34;/\u0026gt; \u0026lt;parameter property=\u0026#34;email\u0026#34; jdbcType=\u0026#34;VARCHAR\u0026#34;/\u0026gt; \u0026lt;parameter property=\u0026#34;activationCode\u0026#34; jdbcType=\u0026#34;CHAR\u0026#34;/\u0026gt; \u0026lt;parameter property=\u0026#34;lastLogin\u0026#34; jdbcType=\u0026#34;TIMESTAMP\u0026#34;/\u0026gt; \u0026lt;parameter property=\u0026#34;id\u0026#34; jdbcType=\u0026#34;INTEGER\u0026#34;/\u0026gt; \u0026lt;/parameterMap\u0026gt; \u0026lt;update id=\u0026#34;update\u0026#34; parameterMap=\u0026#34;userMap\u0026#34;\u0026gt; \u0026lt;![CDATA[ update \u0026#34;user\u0026#34; set username = ?, password = ?, email = ?, activationCode = ?, lastLogin = ?, lastModified = CURRENT_TIMESTAMP where id = ? ]]\u0026gt; \u0026lt;/update\u0026gt; First published on the old anydoby.com blog on 2009-06-06.\n","date":"6 June 2009","externalUrl":null,"permalink":"/articles/derby-ibatis-and-nulls/","section":"Articles","summary":"","title":"Derby, iBATIS and nulls","type":"articles"},{"content":"I\u0026rsquo;ve got really tired of one JTable feature: you press any button and it starts editing current cell. For instance, your application is setup to save on \u0026ldquo;Control+S\u0026rdquo;, but when the table is focused the table intercepts your shortcut and starts editing a cell instead. To fix this go to JTable.processKeyBinding and find the hardcoded flag there JTable.autoStartsEdit (how I love these fckng hidden Swing flags). Now let\u0026rsquo;s put it to work.\ntable.putClientProperty(\u0026#34;JTable.autoStartsEdit\u0026#34;, Boolean.FALSE); All your shortcuts are in your hands :)\nAfter you have done this the table will only start editing if you press F2. If you wish to change that just do the following:\nAction action = table.getActionMap().get(\u0026#34;startEditing\u0026#34;); if (action != null) { table.getInputMap().put(KeyStroke.getKeyStroke(\u0026#34;mykey\u0026#34;), \u0026#34;startEditing\u0026#34;); } Where the hack did I get that startEditing? Look into the BasicTableUI, there all the actions for tables are dscribed. Unfortunatelly in a hidden - private manner.\nFirst published on the old anydoby.com blog on 2009-06-04.\n","date":"4 June 2009","externalUrl":null,"permalink":"/articles/how-to-turn-off-automatic-editing-of-jtable/","section":"Articles","summary":"","title":"How to turn off automatic editing of JTable","type":"articles"},{"content":"So I\u0026rsquo;m again on a new project. Swing and everything around it - fixing bugs in a GUI application with thousands of screens is a tedious job. However I\u0026rsquo;ve found a good helper for Eclipse - the Swing Explorer. Helps browsing the swing compnent tree in runtime.\nThe best practice for writing applications introspectable with Swing Explorer is extending from Swing components, that way you can see exactly the application class, not just the stack trace of component generator.\nFirst published on the old anydoby.com blog on 2009-05-12.\n","date":"12 May 2009","externalUrl":null,"permalink":"/articles/swing-explorer/","section":"Articles","summary":"","title":"Swing Explorer","type":"articles"},{"content":"Objective: do some hard stuff in a stored procedure and make sure that Toplink cache is aware of the modified entities.\nThe solution is quite obvious: return a cursor to a temporary table which contains entity names and IDs which were modified. Easier said than done, Oracle does not allow creation of temporary local tables in procedures for some reason (I\u0026rsquo;ve done that many times within MySQL for example). There is some rudimentary type which they call ARRAY and this type can be used to achieve the desired outcome. I\u0026rsquo;ve spent a lot of time and effort (and consulted many of our Oracle gurus for that matter, now I understand why these guys are so grim) to make it work: you cannot just add a value to a list - you will have to write a function which merges 2 arrays and track the array pointer all the time :) then you\u0026rsquo;ll have to dance woodoo dances to return the values correctly to Toplink. Here is how it went on\u0026hellip;\nSo to add IDs and table names we will need an array:\ncreate or replace TYPE OIDS AS TABLE OF VARCHAR(255); OIDS is an array type (don\u0026rsquo;t let the table keyword fool you, it\u0026rsquo;s not a table, its an old school array), which we return from the procedure. To add redords to this array here is a merger function:\ncreate or replace FUNCTION APPEND_TO_ARRAY(source in oids, destination in out nocopy oids, i in number) return number as new_index number := i; BEGIN IF (source is not null and source.COUNT \u0026gt; 0) THEN destination.EXTEND(source.COUNT); FOR ind IN source.FIRST .. source.LAST LOOP destination(i + ind) := source(ind); END LOOP; new_index := i + source.LAST; END IF; return new_index; END APPEND_TO_ARRAY; It copies elements from source to destination, and i is an index of last element from destination.\nAnd here comes the data cruncher, which produces output:\ncreate or replace procedure myproc(modified_oids OUT NOCOPY oids) is temp_oids oids; v_indx number:=0; // do something update mytable t set t.mycolumn = \u0026#39;bla-bla-bla\u0026#39; returning t.ID || \u0026#39;_mypackage.MyEntity\u0026#39; bulk collect into temp_oids; v_indx := APPEND_TO_ARRAY(temp_oids, modified_oids, v_indx); // this is how every updated looks like Oracle has a nice feature, you can return affected rows from an update, we utilize this when returning table names and modified record IDs into a temporary table, then we merge the temporary table with the output table every time we modify another table. Unfortunately this is the only reasonable way for retrieving output data that I am aware of.\nAnd finally the Java code to invoke procedure and retrieve the data:\nStoredProcedureCall call = new StoredProcedureCall(); call.setProcedureName(\u0026#34;MYPROC\u0026#34;); call.addNamedOutputArgument(\u0026#34;modified_oids\u0026#34;, \u0026#34;modified_oids\u0026#34;, Types.ARRAY, \u0026#34;OIDS\u0026#34;); DatabaseQuery query = new ValueReadQuery(); query.setCall(call); Object result = toplinkSession.executeQuery(query); Object[] resultArray = (Object[])((Array)result).getArray(); In response array we get Strings.\nFirst published on the old anydoby.com blog on 2009-02-02.\n","date":"2 February 2009","externalUrl":null,"permalink":"/articles/retrieving-data-from-stored-procedures-in-toplink/","section":"Articles","summary":"","title":"Retrieving data from stored procedures in Toplink","type":"articles"},{"content":"I guess everybody who worked with web J2EE Security regretted about extreme inflexibility of authentication web tier. Yes, the technology is good and flexible, you can for example stick a JAAS module which will work in any environment and the programmer will not need to mess up with login forms and page protection from one project to another. Yet, what will you tell your customer if he asks for example that after registration user is immediately logged in implicitly? How do you make Tomcat log in a user without showing authentication form or hitting a secured url?\nUsing built-in J2EE APIs you can create a new LoginContext and invoke a login() method. However the web container does not know a thing about the LoginContext and HttpServletRequest.isUserInRole() will repeatedly say false.\nI found a quick and dirty solution, which can be used all alone or together with form based authentication, sorry only in Tomcat. It programmatically \u0026ldquo;logs in\u0026rdquo; a user with a set of roles:\npackage com.anydoby.login; import java.io.IOException; import java.lang.reflect.Field; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.authenticator.AuthenticatorBase; import org.apache.catalina.authenticator.Constants; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.RequestFacade; import org.apache.catalina.connector.Response; import org.apache.catalina.connector.ResponseFacade; import org.apache.catalina.deploy.LoginConfig; import org.apache.catalina.realm.GenericPrincipal; /** * * @author SergeyZ * */ public class ProgrammaticAuthenticator extends AuthenticatorBase { private Field request; private Field response; { Field[] fields = RequestFacade.class.getDeclaredFields(); request = filter(fields, \u0026#34;request\u0026#34;); request.setAccessible(true); fields = ResponseFacade.class.getDeclaredFields(); response = filter(fields, \u0026#34;response\u0026#34;); response.setAccessible(true); } public void authenticate(HttpServletRequest rq, HttpServletResponse rs, String user, String password, List\u0026lt;String\u0026gt; roles) { try { GenericPrincipal principal = new GenericPrincipal(null, user, password, roles); register((Request)request.get(rq), (Response)response.get(rs), principal, Constants.FORM_METHOD, user, password); } catch (Exception e) { throw new RuntimeException(e); } } private Field filter(Field[] fields, String name) { for (Field field : fields) { if (field.getName().equals(name)) { return field; } } return null; } @Override protected boolean authenticate(Request request, Response response, LoginConfig config) throws IOException { throw new UnsupportedOperationException(\u0026#34;Use authenticate(Principal)\u0026#34;); } } After you have programmatically defined that user credentials are correct and have received his roles you call authenticate() and Tomcat will memorize the person. Don\u0026rsquo;t please blame me for using reflections, Tomcat authors left no choice :)\nHere is a little sample which you can use to play around with the concept.\nFirst published on the old anydoby.com blog on 2008-11-17.\n","date":"17 November 2008","externalUrl":null,"permalink":"/articles/programmatic-j2ee-authentication-in-tomcat/","section":"Articles","summary":"","title":"Programmatic J2EE authentication in Tomcat","type":"articles"},{"content":"Today we\u0026rsquo;ve received a strange bug.\nIn one of our projects we are using SSL to protect the pages and data and users download PDF application forms and then do something with them. The problem is - in IE under SSL the download link lead to the following error message from browser:\nFile could not be written to the cache Having searched a little on the web I\u0026rsquo;ve found that this is a known issue of IE and microsoft even suggests a solution to it by changing some registry flag :) can you imagine offering your clients to change something in their registry? So I dug again and found that response contains the following headers: Cache-Control: no-cache and Pragma: no-cache, which I did not add anywhere in the code. These headers cause IE to go crazy.\nThen I debugged Tomcat a little and found a very funny piece of code:\n// Make sure that constrained resources are not cached by web proxies // or browsers as caching can provide a security hole if (disableProxyCaching \u0026amp;\u0026amp; // FIXME: Disabled for Mozilla FORM support over SSL // (improper caching issue) //!request.isSecure() \u0026amp;\u0026amp; !\u0026#34;POST\u0026#34;.equalsIgnoreCase(request.getMethod())) { if (securePagesWithPragma) { // FIXME: These cause problems with downloading office docs // from IE under SSL and may not be needed for newer Mozilla // clients. response.setHeader(\u0026#34;Pragma\u0026#34;, \u0026#34;No-cache\u0026#34;); response.setHeader(\u0026#34;Cache-Control\u0026#34;, \u0026#34;no-cache\u0026#34;); } else { response.setHeader(\u0026#34;Cache-Control\u0026#34;, \u0026#34;private\u0026#34;); } response.setHeader(\u0026#34;Expires\u0026#34;, DATE_ONE); } especially funny are the FIXME lines in production code. All in all Tomcat is adding two extra lines to response headers which no-one has asked him to. So how do I fix that? The location of this code is in org.apache.catalina.authenticator.AuthenticatorBase, and the concrete class will depend on the type of authorization you\u0026rsquo;re using. We did not use JEE authorization so the class was org.apache.catalina.authenticator.NonLoginAuthenticator, this is an Authenticator and a Valve so it can be configured using context.xml. Add the following lines to your war\u0026rsquo;s context.xml:\n\u0026lt;Valve className=\u0026#34;org.apache.catalina.authenticator.NonLoginAuthenticator\u0026#34; securePagesWithPragma=\u0026#34;false\u0026#34;/\u0026gt; This is it :)\nFirst published on the old anydoby.com blog on 2008-06-06.\n","date":"6 June 2008","externalUrl":null,"permalink":"/articles/ie-file-could-not-be-written-to-the-cache/","section":"Articles","summary":"","title":"IE file could not be written to the cache","type":"articles"},{"content":"Spring 2.5 introduced special annotations for configuring web form controllers which helps reduce XML configuration to necessary minimum. In this article I will show how to use most of them to easily map requests to URLs, bind request parameters to method parameters, etc.\nLet\u0026rsquo;s start from explaining the request life-cycle of Spring MVC:\n1. The request hits servlet container which determines that the URL is mapped to spring dispatcher servlet\n2. The servlet searches for request handler using the mappings configured either through XML or in code using annotations\n3. If no handler was found a default handler (if any) is invoked\n4. Prior to handler invocation handler interceptors are executed, if any\n5. A handler adapter is determined for the handler. Handler adapter \u0026ldquo;knows\u0026rdquo; how to process a request using the handler. For example if you use SimpleFormController request parameters will be bound to command object, validators will be invoked and if no errors were detected controller is invoked\n6. Controller returns either an ModelAndView object which contains model objects to be rendered and a view name or an instance of View\n7. If Controller returns null as ModelAndView it is considered that the handler has performed rendering of request and no further processing is required\n8. If Controller returns a ModelAndView with String logical view name a ViewResolver is searched for in the config which attempts to resolve view class. Then the class is instantiated, configured and View.render is invoked\n9. If there are any interceptors assigned to Controller in Spring configs they are invoked after request has been rendered.\nNow let\u0026rsquo;s see how controllers are registered and how to map them to request URLs using Spring 2.5.\nFirst and foremost - in Spring 2.5 almost any instance method can be used as a Controller. Consider this simple example:\n@Controller @RequestMapping( { \u0026#34;/home\u0026#34;, \u0026#34;/products\u0026#34; }) public class HomePage { private final SampleDao dao; @Autowired public HomePage(SampleDao dao) { this.dao = dao; } @RequestMapping(method = RequestMethod.GET, value = \u0026#34;/home\u0026#34;) public void memberPage() { // do smth return nothing - view = home } @SuppressWarnings(\u0026#34;unchecked\u0026#34;) @RequestMapping(method = RequestMethod.GET, value = \u0026#34;/products\u0026#34;) public String productsPage(@RequestParam(\u0026#34;page\u0026#34;) Integer pageNumber, ModelMap map) { map.put(\u0026#34;products\u0026#34;, dao.getProducts(pageNumber)); return \u0026#34;products\u0026#34;; } } A HomePage class is now a Conroller, which is mapped to 2 URLs - /home and /products. It\u0026rsquo;s instantiated by Spring using a one argument constructor. The @Autowired annotation means that we let the framework decide how to configure the controller given the available dependencies. The memberPage() method is here just for the sake of an example - it does nothing and returns nothing. However it is mapped to /home URL. You might ask what view will be rendered when this method is complete? If no String is returned as the view name the URL that this controller is mapped to will be returned by default, in our case the memberPage is mapped to /home, so home will be the view name.\nNow let\u0026rsquo;s look at the second method - it is mapped to /products URL and returns the view name of \u0026ldquo;products\u0026rdquo; explicitly. In addition it utilizes Spring 2.5 ability to automatically fill method arguments with data from request - request parameter page will be automatically converted to Integer and used as method argument. In addition we request that a ModelMap be provided so that we can fill request scope with data which will be rendered by products view. Spring 2.5 offers a wide flexibility for request method arguments: instead of a spring specific ModelMap object you can just request a java.util.Map and fill it with model data, you can bind request parameters using the @RequestParam annotation, you can declare a command class argument and it will be filled with data from request parameters automatically. Consider this example of Product submission:\n@RequestMapping(method = RequestMethod.POST) public String addProduct(@ModelAttribute(\u0026#34;product\u0026#34;) Product product, BindingResult errors, HttpServletRequest rq) { // the method will be provided with product command automatically filled from request parameters // you can use errors object to report any validation errors and forward to form view or redirect to success view // you can access http request/response directly if you wish // @ModelAttribute is optional - by using it you can expose the command object as model attribute } Now for the configuration part - it has been made utterly simple. We have 2 XML files for the config: applicationContext.xml and dispatcher-servlet.xml. The first file is our business layer configuration and dispatcher-servlet.xml is required to configure the DispatcherServlet which invokes controllers.\napplicationContext.xml\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34;?\u0026gt; \u0026lt;beans xmlns=\u0026#34;http://www.springframework.org/schema/beans\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xmlns:aop=\u0026#34;http://www.springframework.org/schema/aop\u0026#34; xmlns:tx=\u0026#34;http://www.springframework.org/schema/tx\u0026#34; xmlns:context=\u0026#34;http://www.springframework.org/schema/context\u0026#34; xmlns:dwr=\u0026#34;http://www.directwebremoting.org/schema/spring-dwr\u0026#34; xmlns:jee=\u0026#34;http://www.springframework.org/schema/jee\u0026#34; xsi:schemaLocation=\u0026#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\u0026#34; default-dependency-check=\u0026#34;none\u0026#34; default-lazy-init=\u0026#34;false\u0026#34;\u0026gt; \u0026lt;bean id=\u0026#34;tilesConfigurer\u0026#34; class=\u0026#34;org.springframework.web.servlet.view.tiles2.TilesConfigurer\u0026#34;\u0026gt; \u0026lt;property name=\u0026#34;definitions\u0026#34;\u0026gt; \u0026lt;list\u0026gt; \u0026lt;value\u0026gt;/WEB-INF/tiles-config/basic-templates.xml\u0026lt;/value\u0026gt; \u0026lt;/list\u0026gt; \u0026lt;/property\u0026gt; \u0026lt;/bean\u0026gt; \u0026lt;bean class=\u0026#34;com.anydoby.spingmvc.dao.SampleDaoImpl\u0026#34;\u0026gt;\u0026lt;/bean\u0026gt; \u0026lt;bean class=\u0026#34;org.springframework.web.servlet.view.UrlBasedViewResolver\u0026#34;\u0026gt; \u0026lt;property name=\u0026#34;viewClass\u0026#34; value=\u0026#34;org.springframework.web.servlet.view.JstlView\u0026#34;\u0026gt;\u0026lt;/property\u0026gt; \u0026lt;property name=\u0026#34;prefix\u0026#34; value=\u0026#34;/WEB-INF/views/tiles/\u0026#34;\u0026gt;\u0026lt;/property\u0026gt; \u0026lt;property name=\u0026#34;suffix\u0026#34; value=\u0026#34;.jsp\u0026#34;\u0026gt;\u0026lt;/property\u0026gt; \u0026lt;/bean\u0026gt; \u0026lt;/beans\u0026gt; We use Tiles2 to easily compose complex pages out of smaller tiles, a simple DAO layer and a ViewResolver which prepends /WEB-INF/views/tiles and appends .jsp suffix to every view name we provide. After this it instantiates JstlView which knows how to render jsp pages. So the home view name becomes /WEB-INF/views/tiles/home.jsp and products -\u0026gt; /WEB-INF/views/tiles/products.jsp. Easy enough.\ndispatcher-servlet.xml\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34;?\u0026gt; \u0026lt;beans xmlns=\u0026#34;http://www.springframework.org/schema/beans\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xmlns:aop=\u0026#34;http://www.springframework.org/schema/aop\u0026#34; xmlns:tx=\u0026#34;http://www.springframework.org/schema/tx\u0026#34; xmlns:context=\u0026#34;http://www.springframework.org/schema/context\u0026#34; xmlns:dwr=\u0026#34;http://www.directwebremoting.org/schema/spring-dwr\u0026#34; xmlns:jee=\u0026#34;http://www.springframework.org/schema/jee\u0026#34; xsi:schemaLocation=\u0026#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\u0026#34; default-dependency-check=\u0026#34;none\u0026#34; default-lazy-init=\u0026#34;false\u0026#34;\u0026gt; \u0026lt;context:component-scan base-package=\u0026#34;com.anydoby.spingmvc.controllers\u0026#34; /\u0026gt; \u0026lt;/beans\u0026gt; This is it for the dispatcher - Spring will automatically search for controllers in the given package. Provided we use auto-wiring we don\u0026rsquo;t have to declare anything else. The long criticized bulky XML configurations are now in the past :)\nThe attachment to this article contains slightly modified version of the discussed sample as a Maven2 project which can be used to play around with mappings/controllers/urls, etc. Type:\nmvn clean package and copy the war file from target folder into Tomcat\u0026rsquo;s webapps to play around.\nFirst published on the old anydoby.com blog on 2008-05-05.\n","date":"5 May 2008","externalUrl":null,"permalink":"/articles/spring-2-5-web-mvc-tutorial/","section":"Articles","summary":"","title":"Spring 2.5 Web MVC tutorial","type":"articles"},{"content":"Shit happens: DWR 2.0.3 does not work properly with Spring 2.5:\norg.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.directwebremoting.org/schema/spring-dwr] Offending resource: ServletContext resource [/WEB-INF/applicationContext.xml] at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68) at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85) at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:80) Had to downgrade to DWR 2.0.1\nFirst published on the old anydoby.com blog on 2008-04-25.\n","date":"25 April 2008","externalUrl":null,"permalink":"/articles/dwr-2-0-3-does-not-work-with-spring-2-5/","section":"Articles","summary":"","title":"DWR 2.0.3 does not work with Spring 2.5","type":"articles"},{"content":"Every time when a task comes to page some big resultset in JSP you have to solve the same problem again and again - how to print correct links with all search criteria and a page index and possibly in a most reusable way. Recently I have finally come up with a simple tag which does this with minimal efforts. The first and foremost - the data transfer object which we will need for the pager to work:\npackage com.anydoby.dao; import java.util.List; /** * @author SergeyZ */ public class ListPage\u0026lt;T\u0026gt; { private int page; private List\u0026lt;T\u0026gt; data; private int total; private int maxPerPage; public ListPage(List\u0026lt;T\u0026gt; data, int page, int total, int maxPerPage) { this.data = data; this.page = page; this.total = total; this.maxPerPage = maxPerPage; } public int getPage() { return page; } public void setPage(int page) { this.page = page; } public List\u0026lt;T\u0026gt; getData() { return data; } public void setData(List\u0026lt;T\u0026gt; data) { this.data = data; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public int getMaxPerPage() { return maxPerPage; } public void setMaxPerPage(int maxPerPage) { this.maxPerPage = maxPerPage; } } This is a trivial list wrapper which we will need to pass to the JSP page: data - a results list, page - current page index (starting with 0), total - total amount of results in a resultset (not less than the total number of entries in data), maxPerPage - max results to show per page.\nAnd here is the tag which outputs the links to result pages:\npackage com.anydoby.utils; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspContext; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.SimpleTagSupport; import com.anydoby.spingmvc.dao.ListPage; /** * @author SergeyZ */ public class PagerTag extends SimpleTagSupport { @SuppressWarnings(\u0026#34;unchecked\u0026#34;) private ListPage page; private String pageParam; public String getPageParam() { return pageParam; } public void setPageParam(String pageParam) { this.pageParam = pageParam; } @SuppressWarnings(\u0026#34;unchecked\u0026#34;) public ListPage getPage() { return page; } @SuppressWarnings(\u0026#34;unchecked\u0026#34;) public void setPage(ListPage page) { this.page = page; } @Override public void doTag() throws JspException, IOException { StringBuffer requestURL = getRequestUrl(); int pagesTotal = page.getTotal() / page.getMaxPerPage(); if (page.getTotal() % page.getMaxPerPage() != 0) { pagesTotal++; } if (pagesTotal \u0026gt; 1) { int startOfPageParam = requestURL.indexOf(pageParam + \u0026#34;=\u0026#34;); if (startOfPageParam != -1) { int endOfPageParam = requestURL.indexOf(\u0026#34;\u0026amp;\u0026#34;, startOfPageParam + pageParam.length()); if (endOfPageParam == -1) { endOfPageParam = requestURL.length(); } requestURL.delete(startOfPageParam, endOfPageParam); } char lastQueryChar = requestURL.charAt(requestURL.length() - 1); if (lastQueryChar != \u0026#39;?\u0026#39; \u0026amp;\u0026amp; lastQueryChar != \u0026#39;\u0026amp;\u0026#39;) { requestURL.append(\u0026#39;\u0026amp;\u0026#39;); } requestURL.append(pageParam).append(\u0026#39;=\u0026#39;); String url = requestURL.toString(); StringBuilder sb = new StringBuilder(); for (int i = 0; i \u0026lt; pagesTotal; i++) { if (page.getPage() != i) { sb.append(\u0026#34;\u0026lt;a href=\\\u0026#34;\u0026#34;).append(url).append(i).append(\u0026#34;\\\u0026#34;\u0026gt;\u0026#34;); sb.append(i + 1); sb.append(\u0026#34;\u0026lt;/a\u0026gt; \u0026#34;); } else { sb.append(\u0026#34;\u0026lt;b\u0026gt;\u0026#34;); sb.append(i + 1); sb.append(\u0026#34;\u0026lt;/b\u0026gt; \u0026#34;); } } getJspContext().getOut().append(sb.toString()); } } private StringBuffer getRequestUrl() { StringBuffer construct = construct(getJspContext(), \u0026#34;javax.servlet.forward.\u0026#34;); if (construct == null) { construct = construct(getJspContext(), \u0026#34;javax.servlet.include.\u0026#34;); } if (construct == null) { PageContext ctx = (PageContext) getJspContext(); HttpServletRequest request = (HttpServletRequest) ctx.getRequest(); construct = request.getRequestURL(); construct.append(\u0026#39;?\u0026#39;); if (request.getQueryString() != null) { construct.append(request.getQueryString()); } } return construct; } private StringBuffer construct(JspContext context, String prefix) { Object uri = context.getAttribute(prefix + \u0026#34;request_uri\u0026#34;, PageContext.REQUEST_SCOPE); if (uri != null) { Object ctxPath = context.getAttribute(prefix + \u0026#34;context_path\u0026#34;, PageContext.REQUEST_SCOPE); Object servletPath = context.getAttribute(prefix + \u0026#34;servlet_path\u0026#34;, PageContext.REQUEST_SCOPE); Object pathInfo = context.getAttribute(prefix + \u0026#34;path_info\u0026#34;, PageContext.REQUEST_SCOPE); Object query = context.getAttribute(prefix + \u0026#34;query_string\u0026#34;, PageContext.REQUEST_SCOPE); StringBuffer buffer = new StringBuffer(); buffer.append(ctxPath).append(servletPath); if (pathInfo != null) { buffer.append(pathInfo); } buffer.append(\u0026#39;?\u0026#39;); if (query != null) { buffer.append(query); } return buffer; } return null; } } The code ensures that the tag automatically determines which url the user is on (it can be hidden if you use for example dispatch or include, and you obviously use it with Spring MVC or Struts).\nAnd here is the taglib.tld, which you will place in the WEB-INF/tags:\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34; ?\u0026gt; \u0026lt;taglib xmlns=\u0026#34;http://java.sun.com/xml/ns/j2ee\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xsi:schemaLocation=\u0026#34;http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd\u0026#34; version=\u0026#34;2.0\u0026#34;\u0026gt; \u0026lt;tlib-version\u0026gt;1.0\u0026lt;/tlib-version\u0026gt; \u0026lt;short-name\u0026gt;r\u0026lt;/short-name\u0026gt; \u0026lt;uri\u0026gt;http://anydoby.com/simpletags\u0026lt;/uri\u0026gt; \u0026lt;tag\u0026gt; \u0026lt;description\u0026gt; Prints a simple pager \u0026lt;/description\u0026gt; \u0026lt;name\u0026gt;pager\u0026lt;/name\u0026gt; \u0026lt;tag-class\u0026gt;com.anydoby.utils.PagerTag\u0026lt;/tag-class\u0026gt; \u0026lt;body-content\u0026gt;empty\u0026lt;/body-content\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;page\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;true\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;type\u0026gt;com.anydoby.dao.ListPage\u0026lt;/type\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;pageParam\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;true\u0026lt;/required\u0026gt; \u0026lt;type\u0026gt;java.lang.String\u0026lt;/type\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;/tag\u0026gt; \u0026lt;/taglib\u0026gt; on a JSP page this tag will look like this:\n\u0026lt;%@ taglib prefix=\u0026#34;r\u0026#34; uri=\u0026#34;http://anydoby.com/simpletags\u0026#34; %\u0026gt; ... results displayed ... \u0026lt;r:pager page=\u0026#34;${results}\u0026#34; pageParam=\u0026#34;page\u0026#34;/\u0026gt; The tag constructs links to current url (keeping all request parameters) by adding a page parameter (chose any name you like), with the number of next result page.\nFirst published on the old anydoby.com blog on 2008-04-25.\n","date":"25 April 2008","externalUrl":null,"permalink":"/articles/simple-paging-with-jsp-tags/","section":"Articles","summary":"","title":"Simple paging with JSP tags","type":"articles"},{"content":"Today I noticed another confusing feature of MySQL. It all started like this: I have a table with 3 columns of type TIMESTAMP. Two of them are system: dateCreated and lastModified. I created 2 triggers which fill the data with current time when the rows are inserted and updated respectively. As for the 3-rd column it is set manually. Then I noticed a funny thing - when I update a row in that table the 3-rd column will change to current time. I have managed to create a simple example of how to reproduce this:\ncreate table test ( id integer primary key auto_increment , value integer , expires timestamp ); insert into test (value,expires) values (1, \u0026#39;2010-10-20 10:00:00.0\u0026#39;); update test set value = 2 where id = 1; The expires will be updated with current datetime, but I never asked it to change. This can be cured by changing datatype to DATETIME. Perhaps I am missing something about MySQL documentation? But I am sure there is nothing in it about TIMESTAMP being automatically changed to current timestamp.\nPS: MySQL version 5.0\nFirst published on the old anydoby.com blog on 2008-04-16.\n","date":"16 April 2008","externalUrl":null,"permalink":"/articles/cunning-timestamps-in-mysql/","section":"Articles","summary":"","title":"Cunning Timestamps in MySQL","type":"articles"},{"content":"One of our porject forms has fields of type java.util.Date. At first we used String to store the value and then used regexp validator to check if the date was valid. When we actually needed to convert it to Date we had to do it manually. Naturally this is not a very clean solution, especially if you have to deal with it oftern. So I found a simple solution - wrote my own PropertyEditor for dates and attached it to my forms\npackage com.anydoby.web; import java.beans.PropertyEditorSupport; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; /** * Supports transformation of dates to strings and vice versa using the specified date format. If * string representation could not be parsed correctly, returns null date. * * @author SergeyZ * */ public class DateEditor extends PropertyEditorSupport { private final String datePattern; private final Pattern textValidator; public DateEditor(String datePattern, Pattern textValidator) { this.datePattern = datePattern; this.textValidator = textValidator; } @Override public String getAsText() { SimpleDateFormat format = new SimpleDateFormat(datePattern); Object value = getValue(); if (value == null) { return null; } String string = format.format(value); return string; } @Override public void setAsText(String text) throws IllegalArgumentException { if (StringUtils.isBlank(text)) { setValue(null); } else { if (!textValidator.matcher(text).matches()) { throw new IllegalArgumentException(\u0026#34;Invalid pattern\u0026#34;); } SimpleDateFormat format = new SimpleDateFormat(datePattern); format.setLenient(false); try { Date parse = format.parse(text); setValue(parse); } catch (ParseException e) { throw new IllegalArgumentException(e); } } } } and in the Controller\u0026rsquo;s initBinder\nPattern datePattern = Pattern.compile(\u0026#34;\\\\d{1,2}/\\\\d{1,2}/\\\\d{4}\u0026#34;); DateEditor dateEditor = new DateEditor(\u0026#34;dd/MM/yyyy\u0026#34;, datePattern); binder.registerCustomEditor(java.util.Date.class, dateEditor); Everything now works ok - Spring converts strings to dates and binds to respective properties. However we got another problem - if an invalid date is entered then the form displays 2 errors - one comes from the databinder and another one from validator, which finds that required field is null. Not very user-friendly. I started thinking and found no better solution than to simply write a custom tag which displays errors:\npackage com.anydoby.util; import javax.servlet.jsp.JspException; import org.apache.commons.lang.StringUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.servlet.support.BindStatus; import org.springframework.web.servlet.tags.form.ErrorsTag; import org.springframework.web.servlet.tags.form.TagWriter; /** * This extension to spring tags will show only first error of every field it displays. * @author SergeyZ * */ public class FirstErrorTag extends ErrorsTag { private static final long serialVersionUID = 716823632508216981L; @Override protected void renderDefaultContent(TagWriter tagWriter) throws JspException { tagWriter.startTag(getElement()); writeDefaultAttributes(tagWriter); String delimiter = ObjectUtils.getDisplayString(evaluate(\u0026#34;delimiter\u0026#34;, getDelimiter())); BindStatus status = getBindStatus(); String path = status.getPath(); if (StringUtils.isBlank(path)) { String[] errorMessages = status.getErrorMessages(); for (int i = 0; i \u0026lt; errorMessages.length; i++) { String errorMessage = errorMessages[i]; if (i \u0026gt; 0) { tagWriter.appendValue(delimiter); } tagWriter.appendValue(getDisplayString(errorMessage)); } tagWriter.endTag(); } else { String[] errorMessages = status.getErrorMessages(); if (errorMessages.length \u0026gt; 0) { tagWriter.appendValue(getDisplayString(errorMessages[0])); } tagWriter.endTag(); } } } and the taglib.tld\n\u0026lt;!DOCTYPE taglib PUBLIC \u0026#34;-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN\u0026#34; \u0026#34;http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd\u0026#34;\u0026gt; \u0026lt;taglib\u0026gt; \u0026lt;tlib-version\u0026gt;1.0\u0026lt;/tlib-version\u0026gt; \u0026lt;jsp-version\u0026gt;2.0\u0026lt;/jsp-version\u0026gt; \u0026lt;short-name\u0026gt;a\u0026lt;/short-name\u0026gt; \u0026lt;uri\u0026gt;http://anydoby.com/tags\u0026lt;/uri\u0026gt; \u0026lt;tag\u0026gt; \u0026lt;name\u0026gt;errors\u0026lt;/name\u0026gt; \u0026lt;tag-class\u0026gt;com.anydoby.util.FirstErrorTag\u0026lt;/tag-class\u0026gt; \u0026lt;body-content\u0026gt;JSP\u0026lt;/body-content\u0026gt; \u0026lt;description\u0026gt;Renders field errors in an HTML \u0026#39;span\u0026#39; tag.\u0026lt;/description\u0026gt; \u0026lt;variable\u0026gt; \u0026lt;name-given\u0026gt;messages\u0026lt;/name-given\u0026gt; \u0026lt;variable-class\u0026gt;java.util.List\u0026lt;/variable-class\u0026gt; \u0026lt;/variable\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;path\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;Path to errors object for data binding\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;id\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Standard Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;htmlEscape\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;Enable/disable HTML escaping of rendered values.\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;delimiter\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;Delimiter for displaying multiple error messages. Defaults to the br tag.\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;cssClass\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;Equivalent to \u0026#34;class\u0026#34; - HTML Optional Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;cssStyle\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;Equivalent to \u0026#34;style\u0026#34; - HTML Optional Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;lang\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Standard Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;title\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Standard Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;dir\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Standard Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;tabindex\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Standard Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;onclick\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Event Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;ondblclick\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Event Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;onmousedown\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Event Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;onmouseup\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Event Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;onmouseover\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Event Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;onmousemove\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Event Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;onmouseout\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Event Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;onkeypress\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Event Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;onkeyup\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Event Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;onkeydown\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;HTML Event Attribute\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;attribute\u0026gt; \u0026lt;name\u0026gt;element\u0026lt;/name\u0026gt; \u0026lt;required\u0026gt;false\u0026lt;/required\u0026gt; \u0026lt;rtexprvalue\u0026gt;true\u0026lt;/rtexprvalue\u0026gt; \u0026lt;description\u0026gt;Specifies the HTML element that is used to render the enclosing errors.\u0026lt;/description\u0026gt; \u0026lt;/attribute\u0026gt; \u0026lt;/tag\u0026gt; \u0026lt;/taglib\u0026gt; The tag is used just as regular Spring errors tag, but it displays only one error it it\u0026rsquo;s a field error.\nFirst published on the old anydoby.com blog on 2008-04-11.\n","date":"11 April 2008","externalUrl":null,"permalink":"/articles/single-error-message-per-form-field-in-spring-mvc/","section":"Articles","summary":"","title":"Single error message per form field in Spring MVC","type":"articles"},{"content":"I\u0026rsquo;ve noticed a funny quirk in Hibernate 3. I have a table Product and this product can have say several Images. In the mappings I specify Product.images dependency as fetch=EAGER, i.e. I request a JOIN on Image table. If a product has 3 images, then the ResultSet will contain 3 almost identical records differing just by the content of joined Image record. It is natural to expect Hibernate to merge these 3 records into a single Product (they have the same id column) and 3 Image children. However this is not the case if you are using the DetachedCriteria:\nDetachedCriteria criteria = DetachedCriteria.forClass(entityClass); criteria = criteria.addOrder(ascending ? Order.asc(orderBy) : Order.desc(orderBy)); List\u0026lt;T\u0026gt; list = getHibernateTemplate().findByCriteria(criteria); The resulting list will contain 3(!!!) Product objects with the same id :) each having one child Image.\nI had to rewrite the search query like this:\nList find = getHibernateTemplate().find(\u0026#34;from \u0026#34; + entityClass.getSimpleName() + \u0026#34; order by \u0026#34; + orderBy + \u0026#34; \u0026#34; + (ascending ? \u0026#34; asc \u0026#34; : \u0026#34; desc\u0026#34;)); This one groups results correctly.\nFirst published on the old anydoby.com blog on 2008-04-09.\n","date":"9 April 2008","externalUrl":null,"permalink":"/articles/fun-with-hibernate-duplicates/","section":"Articles","summary":"","title":"Fun with Hibernate duplicates","type":"articles"},{"content":"This morning I had to setup one MySQL database on my home computer (Zenwalk Linux 5.0), everything went smoothly until I needed to connect to the database from Java using the mysql-connector. What surprised my, MySQL Admin front end connected to the database ok, and with the JDBC I see the following error:\nAn error occured while establishing the connection. Type: com.mysql.jdbc.CommunicationsException Error Code: 0 SQL State: 08S01 Message: Communications link failure due to underlying exception: ** BEGIN NESTED EXCEPTION ** java.net.ConnectException MESSAGE: Connection refused STACKTRACE: java.net.ConnectException: Connection refused at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333) at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366) at java.net.Socket.connect(Socket.java:519) at java.net.Socket.connect(Socket.java:469) at java.net.Socket.\u0026lt;init\u0026gt;(Socket.java:366) at java.net.Socket.\u0026lt;init\u0026gt;(Socket.java:208) at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:256) at com.mysql.jdbc.MysqlIO.\u0026lt;init\u0026gt;(MysqlIO.java:271) at com.mysql.jdbc.Connection.createNewIO(Connection.java:2744) at com.mysql.jdbc.Connection.\u0026lt;init\u0026gt;(Connection.java:1553) at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:285) at java.sql.DriverManager.getConnection(DriverManager.java:582) at java.sql.DriverManager.getConnection(DriverManager.java:154) at com.onseven.dbvis.wrapper.DriverManagerImpl.getConnection(Unknown Source) at com.onseven.dbvis.sql.N.İ(Unknown Source) at com.onseven.dbvis.sql.N.access$200(Unknown Source) at com.onseven.dbvis.sql.N$A.execute(Unknown Source) at se.pureit.util.ThreadCommand.runExecute(ThreadCommand.java:163) at se.pureit.util.ThreadCommand.run(ThreadCommand.java:143) at java.lang.Thread.run(Thread.java:619) ** END NESTED EXCEPTION ** Last packet sent to the server was 1 ms ago. I started digging and here is what I dug out: by default on Slakware (and I guess on many other linuxes) MySQL is closed to TCP/IP connections (which Java uses to connect to the server), in order to enable networking you will have to comment the following line in your /etc/my.cnf:\nskip-networking And that worked for me.\nFirst published on the old anydoby.com blog on 2008-03-29.\n","date":"29 March 2008","externalUrl":null,"permalink":"/articles/connection-refused-from-mysql/","section":"Articles","summary":"","title":"Connection refused from MySQL","type":"articles"},{"content":"I have noticed long ago that SimpleDateFormat parses dates rather funny, for example 18/18/1908 when parsed using this pattern MM/dd/yyyy will be converted to date: 06/18/1909. This is 100% legal from the DateFormat point of view - day overflow will roll the month one point up, and month overflow rolls the year. This is ok for computer sense, however this is against common sense of a human.\nHow do we override this? Set the lenient flag to false, this will enforce stricter rules for date validation - there will never be a 18 month in a GregorianCalendar:\nSimpleDateFormat format = new SimpleDateFormat(\u0026#34;MM/dd/yyyy\u0026#34;); format.setLenient(false); Date date = format.parse(date); .... First published on the old anydoby.com blog on 2008-03-20.\n","date":"20 March 2008","externalUrl":null,"permalink":"/articles/how-to-correctly-parse-dates-in-java/","section":"Articles","summary":"","title":"How to correctly parse dates in Java","type":"articles"},{"content":"It\u0026rsquo;s been quite a while since Tiles2 had been released, and no sings that there would ever be a possibility to use anything except JSPs with it. As I\u0026rsquo;m keen on Velocity for its simplicity and performance, I patiently waited until someone would write an integration layer for it. Time passed and noone did that, so here I come and write one of my own :)\nWelcome to see and test it for yourself here.\nAny bugs or comments are welcome - post them in this topic.\nPS: BTW this blog uses the newly brewed Velocity Tiles2 plugin :)\nFirst published on the old anydoby.com blog on 2008-03-19.\n","date":"19 March 2008","externalUrl":null,"permalink":"/articles/spring-mvc-tiles2-velocity/","section":"Articles","summary":"","title":"Spring MVC + Tiles2 + Velocity","type":"articles"},{"content":"Java 6 introduced basic integration with the host OS desktop. It now has the SystemTray and TrayIcon classes. So, how do we minimize an application to system tray using them?\nThe idea is quite simple - when the window is iconified, for example, we make it invisible, and add a tray icon. The tray icon has an ActionListener attached to it and when the user double-click on it the application\u0026rsquo;s previous state is restored. Quite simple. Let\u0026rsquo;s look at the code to do that:\npackage com.anydoby.minimize; import static java.awt.SystemTray.getSystemTray; import java.awt.AWTException; import java.awt.Image; import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.net.URL; import javax.swing.JFrame; /** * * @author SergeyZ * */ public class MainWindow extends JFrame { private static final long serialVersionUID = 4570679418654300776L; public MainWindow() { super(\u0026#34;Minimizer\u0026#34;); setDefaultCloseOperation(EXIT_ON_CLOSE); URL resource = getClass().getResource(\u0026#34;/icon.gif\u0026#34;); Image image = Toolkit.getDefaultToolkit().getImage(resource); setIconImage(image); if (SystemTray.isSupported()) { final TrayIcon icon = new TrayIcon(image); icon.setToolTip(\u0026#34;Task Logger\u0026#34;); icon.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { MainWindow.this.setVisible(true); MainWindow.this.setExtendedState(MainWindow.NORMAL); getSystemTray().remove(icon); } }); addWindowListener(new WindowAdapter() { @Override public void windowIconified(WindowEvent e) { MainWindow.this.setVisible(false); try { getSystemTray().add(icon); } catch (AWTException e1) { e1.printStackTrace(); } } }); } setSize(100, 100); } public static void main(String[] args) { MainWindow window = new MainWindow(); window.setVisible(true); } } You can download an eclipse project with working example here.\nPS: tested this on my home laptop with Zenwalk installed - does not work - see this bug. As an alternative you can try jdesktop, which as seems to be working better (quite strange, as JDIC was the predecessor of desktop integration implementation for Mustang).\nFirst published on the old anydoby.com blog on 2008-03-15.\n","date":"15 March 2008","externalUrl":null,"permalink":"/articles/minimizing-to-tray-in-java-6/","section":"Articles","summary":"","title":"Minimizing to tray in Java 6","type":"articles"},{"content":"There are two opposite oppinions on java certificates: the first is that the mean and give you nothing, the second is that it helps get a better job and request much bigger salary.\nMy oppinion is that it is a nice way to make you study hard for a while to get to the \u0026ldquo;next level\u0026rdquo;. The certification books help you systematize your knowledge, which you received at your work. As usually, one should not overvalue the certificate itself :) I personally know several guys with a bunch of certificates, whom I would never hire for a decent job :)\nSo the very first Java certificate is the Sun Certified Java Programmer (SCJP). It is relatively easy to get (at least I don\u0026rsquo;t know anybody who had failed). It took me only a year of working experience (first Java year) and later - a month of relaxed reading in the evening. I don\u0026rsquo;t remember exactly how the book was called, it had something like \u0026ldquo;exam cram\u0026rdquo; :) in its name. This certificate made me think like a compiler while looking at the Java code, a \u0026ldquo;power programmer\u0026rdquo; you know. What I\u0026rsquo;ve read some programmers don\u0026rsquo;t bother to know even despite their 5 year experience in Java.\nThe second exam was yet another beast. This is the Sun Certified Java Developer (SCJD). It is composed of two parts - first you write an app, and wait for assignment evaluation results. It took Sun more than a month to evaluate it in my case, so be patient. After the assignment had been accepted you will write a short essay - answer questions on your product. The main goal of this whole thing is to make sure you can follow the requirements, be it a hint or explicit MUST. The technologies used - Swing for the client part (with every new JDK this task becomes easier), RMI for server connection. All in all the assignment was quite amusing. I liked it actually. That\u0026rsquo;s why it is so hard to compose a book on this exam - it is always different. I have however found and read a book on it, the name also contained \u0026ldquo;exam cram\u0026rdquo; :) Won\u0026rsquo;t tell you if it helped a lot, however I caught the essential idea - you\u0026rsquo;re gonna make it if you try. Writing the application took me a whole of 2 months, I did not write every day and mostly did this at work (my wife does not let me sit in front of a computer at home :)) Afterwards I counted the amount of time it took me to write the application - about 60 hours. Most of the time was spent on validation and testing. I received a rather good score - some 89%. The maximum was for Locking (which I did not expect), as for the GUI it was only 75%..\nThe third certificate - Sun Certified Web Components Developer (SCWCD), I received it without much previous experience in the topic. We just expected a big web project at that time and I decided to \u0026ldquo;read a little about the web\u0026rdquo;. I recommend you start with the Servlets specification. It is very simple and straightforward - just the dos and don\u0026rsquo;ts. As for the JSP I read the book \u0026ldquo;SCWCD study kit\u0026rdquo; by Paul Sanghera. It has a lot of pages, which are not all necessarily useful. However I still use this book as a web technologies reference. Pay close attention to web.xml tags, their names and even positions in the document. This is a very useful knowledge for the exam, however there is little use in real life for that - do you edit xml files in notepad? This ceritifcation brought me the status of living encyclopedia on Java web technologies. In our team I am the one to talk to if you have a tricky question :)\nI managed to order the fourth certificate just one day before it officially ceased to exist - too old version of EJB. This is the Sun Certified Business Components Developer 1.3 (SCBCD). Really nothing to talk about, as there is a newer version of this exam already, and there are no book on the exam anyway. I read one book on it, the Paul Sanghera\u0026rsquo;s \u0026ldquo;SCBCD study guide\u0026rdquo;, however this is not the definitive guide for passing. For a quick exam cram you can use this wonderful site. All certificates are concisely covered there. Another good free resource with a lot of exam questions. Just before the exam I read the EJB specification and understood that all my previous efforts were in vain - the spec is the best source for preparation. It contains a lot of figures and what is more precious - it has little tables with bean state diagrams, these tables will answer 80% of exam questions (pay close attention to where in the bean code you can invoke transactional, security methods, etc.) I passed the test with 98% :) So if you are going to take a new version of this exam, don\u0026rsquo;t hesitate - just read the EJB 3.0 spec and you\u0026rsquo;re ready.\nFirst published on the old anydoby.com blog on 2008-03-14.\n","date":"14 March 2008","externalUrl":null,"permalink":"/articles/a-story-of-my-java-certificates/","section":"Articles","summary":"","title":"A story of my Java certificates","type":"articles"},{"content":"Recently I\u0026rsquo;ve found that using Tiles2 is not all that fun if your domain objects tend to throw exceptions at rendering time. I know it not right thing to do of course, but anyway - is there a recipe to make Tiles show the errors in individual tiles?\nThank\u0026rsquo;s god it\u0026rsquo;s all open source and you can plug and extend nearly everything.\nSo here is how I did this with Spring MVC, JSP\u0026rsquo;s and Tiles2.\nFirst we need to create a custom TilesContextFactory. Since I am using JSP for rendering on my project I will naturally extend the JspTilesContextFactory:\npackage com.anydoby.web; import java.io.IOException; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.ServletRequest; import javax.servlet.jsp.PageContext; import org.apache.tiles.TilesApplicationContext; import org.apache.tiles.context.TilesRequestContext; import org.apache.tiles.jsp.context.JspTilesContextFactory; import org.apache.tiles.jsp.context.JspTilesRequestContext; import org.apache.tiles.jsp.context.JspUtil; /** * This context factory will delegate execution to the {@link JspTilesContextFactory} except for * creation of request context. The request context this factory generates is able to handle * exceptions by forwarding an exception to a pre-configured web page for rendering. * * @author SergeyZ * */ public class ExceptionExposingContextFactory extends JspTilesContextFactory { private static final String ERROR_PAGE_PATH = \u0026#34;errorPagePath\u0026#34;; private String errorPage; @Override public void init(Map\u0026lt;String, String\u0026gt; configParameters) { super.init(configParameters); errorPage = configParameters.get(ERROR_PAGE_PATH); } @Override public TilesRequestContext createRequestContext(TilesApplicationContext context, Object... requestItems) { if (requestItems.length == 1) { ServletContext servletContext = getServletContext(context); if (servletContext != null) { final PageContext ctx = (PageContext)requestItems[0]; return new JspTilesRequestContext(servletContext, ctx) { @Override public void include(String path) throws IOException { try { JspUtil.doInclude(ctx, path, false); } catch (Exception e) { ServletRequest rq = ctx.getRequest(); rq.setAttribute(\u0026#34;exception\u0026#34;, e); super.include(errorPage); rq.removeAttribute(\u0026#34;exception\u0026#34;); } } }; } } return null; } } This would be enough if only the init method were invoked at factory creation. In fact the default Tiles2 initialization pipeline omits initialization of underlying rendering factories that it creates. That\u0026rsquo;s a shame :(\nHowever it is very simple to extend from the basic configurer:\npackage com.anydoby.web; import java.lang.reflect.Field; import java.util.Map; import org.apache.tiles.context.ChainedTilesContextFactory; import org.apache.tiles.context.TilesContextFactory; /** * This context factory will initialize the factories which it created using the * {@link TilesContextFactory#init(java.util.Map)}. * @author SergeyZ * */ public class InitalizingChainedContextFactory extends ChainedTilesContextFactory { @Override public void init(Map\u0026lt;String, String\u0026gt; configParameters) { super.init(configParameters); try { Field field = getClass().getSuperclass().getDeclaredField(\u0026#34;factories\u0026#34;); field.setAccessible(true); TilesContextFactory[] factories = (TilesContextFactory[])field.get(this); field.setAccessible(false); for (TilesContextFactory tilesContextFactory : factories) { tilesContextFactory.init(configParameters); } } catch (Exception e) { throw new RuntimeException(e); } } } Unfortunately the ChainedTilesContextFactory was not designed for extensibility, so I have to make an ugly hack - lookup factories using the private field access.\nAnd now the easiest part - Tiles2 configuration with Spring:\n\u0026lt;bean id=\u0026#34;tilesConfigurer\u0026#34; class=\u0026#34;org.springframework.web.servlet.view.tiles2.TilesConfigurer\u0026#34;\u0026gt; \u0026lt;property name=\u0026#34;definitions\u0026#34;\u0026gt; \u0026lt;list\u0026gt; \u0026lt;value\u0026gt;/WEB-INF/config/tiles-defs.xml\u0026lt;/value\u0026gt; \u0026lt;/list\u0026gt; \u0026lt;/property\u0026gt; \u0026lt;property name=\u0026#34;useMutableTilesContainer\u0026#34; value=\u0026#34;true\u0026#34;\u0026gt;\u0026lt;/property\u0026gt; \u0026lt;property name=\u0026#34;tilesProperties\u0026#34;\u0026gt; \u0026lt;props\u0026gt; \u0026lt;prop key=\u0026#34;org.apache.tiles.context.TilesContextFactory\u0026#34;\u0026gt; com.anydoby.web.InitalizingChainedContextFactory \u0026lt;/prop\u0026gt; \u0026lt;prop key=\u0026#34;org.apache.tiles.context.ChainTilesContextFactory.FACTORY_CLASS_NAMES\u0026#34;\u0026gt; org.apache.tiles.servlet.context.ServletTilesContextFactory, com.anydoby.web.ExceptionExposingContextFactory \u0026lt;/prop\u0026gt; \u0026lt;prop key=\u0026#34;errorPagePath\u0026#34;\u0026gt;/WEB-INF/views/error.jsp\u0026lt;/prop\u0026gt; \u0026lt;/props\u0026gt; \u0026lt;/property\u0026gt; \u0026lt;/bean\u0026gt; The error page is hidden from users in WEB-INF/views.\nFirst published on the old anydoby.com blog on 2008-02-20.\n","date":"20 February 2008","externalUrl":null,"permalink":"/articles/how-to-make-tiles2-with-spring-mvc-not-hide-rendering-except/","section":"Articles","summary":"","title":"How to make Tiles2 with Spring MVC not hide rendering exceptions","type":"articles"},{"content":"A few days ago I saw a strange and funny message while viewing a very long jsp\nSEVERE: Servlet.service() for servlet jsp threw exception org.apache.jasper.JasperException: Unable to compile class for JSP: An error occurred at line: 69 in the generated java file The code of method _jspService(HttpServletRequest, HttpServletResponse) is exceeding the 65535 bytes limit Stacktrace: at org.apache.jasper.compiler.DefaultErrorHandler.javacError(DefaultErrorHandler.java:92) at org.apache.jasper.compiler.ErrorDispatcher.javacError(ErrorDispatcher.java:330) at org.apache.jasper.compiler.JDTCompiler.generateClass(JDTCompiler.java:423) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:308) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:286) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:273) It appears this error has a very ancient history :) It surprises me that the error has not been fixed since. This is the usual problem of java - in order to stay backward compatible even its own bugs have to live on to next JDK versions.\nThe only simple solution I found is to split the page and use .\nFirst published on the old anydoby.com blog on 2008-02-07.\n","date":"7 February 2008","externalUrl":null,"permalink":"/articles/too-long-method-size/","section":"Articles","summary":"","title":"Too long method size","type":"articles"},{"content":"Today we are going to talk about sorting and paging very large tables using JSF standard components. To tell the truth I had no satisfying solution to this problem since I have started dealing with JSF, because neither MyFaces, nor Tomahawk offer good components for displaying large tables with sorting an paging. All the table components are fit only for small dataset sizes, which are stored in memory. If the dataset is too large to hold it in RAM, apache wiki offers a simple recipe.\nThis sample is very good, and demostrates the general approach to dealing with large datatables, but it is no good when you need to sort the data. If you attempt to turn on sorting within the table component, your database will be literally flooded with requests. To sort the data, all the records need to be fetched, though it is done in portions and does not consume too much memory, it awfully spams the database. I did not want to write the whole component from scratch, so I have found a temporary workaround - added sorting and paging logic to a managed bean and added commandLinks to go to next/previos page and to do sorting. What I lacked however, were the paging links 1,2,3,4,5\u0026hellip;. which I found too difficult to incorporate into existing component.\nWell everything good ends sometime and our customer requested paging to be \u0026ldquo;like at Google\u0026rdquo;. So I had to turn back to the and had to study JSF once again and write my own component. This is what I\u0026rsquo;ve got in the end.\nHaving read the code of and , I realized that writing the whole component from scratch would be the worst nightmare (given the fact that I hate JSF). However I have found a way to extend the existing component and make it act as I want. In the end it appeared that the amount of code was not that great. The whole project for the component can be downloaded from here.\nI took the code from apache wiki as the basis, tweaking it along the way to get the best performance.\nThis is the code for results page:\npackage com.anydoby.jsfpager; import java.io.Serializable; import java.util.List; /** * A simple class that represents a \u0026#34;page\u0026#34; of data out of a longer set, ie * a list of objects together with info to indicate the starting row and * the full size of the dataset. EJBs can return instances of this type * when returning subsets of available data. */ public class DataPage\u0026lt;T\u0026gt; implements Serializable { private static final long serialVersionUID = -5211047724709570419L; private int startRow; private List\u0026lt;T\u0026gt; data; /** * Create an object representing a sublist of a dataset. * * @param startRow is the index within the complete dataset * of the first element in the data list. * * @param data is a list of consecutive objects from the * dataset. */ public DataPage(int startRow, List\u0026lt;T\u0026gt; data) { this.startRow = startRow; this.data = data; } /** * Return the offset within the full dataset of the first * element in the list held by this object. */ public int getStartRow() { return startRow; } /** * Return the list of objects held by this object, which * is a continuous subset of the full dataset. */ public List\u0026lt;T\u0026gt; getData() { return data; } } This DataModel ensures paging:\npackage com.anydoby.jsfpager; import java.io.Serializable; import javax.faces.model.DataModel; /** * A special type of JSF DataModel to allow a datatable and datascroller * to page through a large set of data without having to hold the entire * set of data in memory at once. * \u0026lt;p\u0026gt; * Any time a managed bean wants to avoid holding an entire dataset, * the managed bean should declare an inner class which extends this * class and implements the fetchData method. This method is called * as needed when the table requires data that isn\u0026#39;t available in the * current data page held by this object. * \u0026lt;p\u0026gt; * This does require the managed bean (and in general the business * method that the managed bean uses) to provide the data wrapped in * a DataPage object that provides info on the full size of the dataset. */ public abstract class PagedListDataModel\u0026lt;T\u0026gt; extends DataModel implements Serializable { int pageSize; int rowIndex = -1; DataPage\u0026lt;T\u0026gt; page; private int datasetSize = -1; private int lastStart; private int lastSize; /* * Create a datamodel that pages through the data showing the specified * number of rows on each page. */ public PagedListDataModel(int pageSize) { this.pageSize = pageSize; } /** * Not used in this class; data is fetched via a callback to the * fetchData method rather than by explicitly assigning a list. */ @Override public void setWrappedData(Object o) { throw new UnsupportedOperationException(\u0026#34;setWrappedData\u0026#34;); } @Override public int getRowIndex() { return rowIndex; } /** * Specify what the \u0026#34;current row\u0026#34; within the dataset is. Note that * the UIData component will repeatedly call this method followed * by getRowData to obtain the objects to render in the table. */ @Override public void setRowIndex(int index) { rowIndex = index; } /** * Return the total number of rows of data available (not just the * number of rows in the current page!). */ @Override public int getRowCount() { if (datasetSize == -1) { datasetSize = getDatasetSize(); } return datasetSize; } /** * Return the total number of rows of data available (not just the * number of rows in the current page!). */ protected abstract int getDatasetSize(); /** * Return a DataPage object; if one is not currently available then * fetch one. Note that this doesn\u0026#39;t ensure that the datapage * returned includes the current rowIndex row; see getRowData. */ private DataPage\u0026lt;T\u0026gt; getPage() { if (page != null) { return page; } int rowIndex = getRowIndex(); int startRow = rowIndex; if (rowIndex == -1) { // even when no row is selected, we still need a page // object so that we know the amount of data available. startRow = 0; } // invoke method on enclosing class page = fetchPageInternal(startRow, pageSize); return page; } /** * Return the object corresponding to the current rowIndex. * If the DataPage object currently cached doesn\u0026#39;t include that * index then fetchPage is called to retrieve the appropriate page. */ @Override public Object getRowData() { if (rowIndex \u0026lt; 0) { throw new IllegalArgumentException( \u0026#34;Invalid rowIndex for PagedListDataModel; not within page\u0026#34;); } // ensure page exists; if rowIndex is beyond dataset size, then // we should still get back a DataPage object with the dataset size // in it... if (page == null) { page = fetchPageInternal(rowIndex, pageSize); } // Check if rowIndex is equal to startRow, // useful for dynamic sorting on pages if (rowIndex == page.getStartRow()) { page = fetchPageInternal(rowIndex, pageSize); } int datasetSize = getRowCount(); int startRow = page.getStartRow(); int nRows = page.getData().size(); int endRow = startRow + nRows; if (rowIndex \u0026gt;= datasetSize) { throw new IllegalArgumentException(\u0026#34;Invalid rowIndex\u0026#34;); } if (rowIndex \u0026lt; startRow) { page = fetchPageInternal(rowIndex, pageSize); startRow = page.getStartRow(); } else if (rowIndex \u0026gt;= endRow) { page = fetchPageInternal(rowIndex, pageSize); startRow = page.getStartRow(); } return page.getData().get(rowIndex - startRow); } private DataPage\u0026lt;T\u0026gt; fetchPageInternal(int start, int size) { if (lastStart != start || lastSize != size || page == null) { page = fetchPage(start, size); lastSize = size; lastStart = start; } return page; } @Override public Object getWrappedData() { return getPage().getData(); } /** * Return true if the rowIndex value is currently set to a * value that matches some element in the dataset. Note that * it may match a row that is not in the currently cached * DataPage; if so then when getRowData is called the * required DataPage will be fetched by calling fetchData. */ @Override public boolean isRowAvailable() { int rowCount = getRowCount(); if (rowCount \u0026lt; 1) { return false; } int rowIndex = getRowIndex(); if (rowIndex \u0026lt; 0) { return false; } else { return !(rowIndex \u0026gt;= getRowCount()); } } /** * Method which must be implemented in cooperation with the * managed bean class to fetch data on demand. */ public abstract DataPage\u0026lt;T\u0026gt; fetchPage(int startRow, int pageSize); } The rest of the code allows us to use a custom component and sort the data manually:\npackage com.anydoby.jsfpager; /** * This is the base class for datamodels returned by the beans, which want their * contents be sortable and pageable in the most efficient way. Subclasses can get * the sortColumn and ascending properties during resultset retrieval. * * @author szolotaryov * * Oct 10, 2007 */ public abstract class SortablePagedDataModel\u0026lt;T\u0026gt; extends PagedListDataModel\u0026lt;T\u0026gt; { private static final long serialVersionUID = -777764054824546815L; private String sortColumn; private boolean sortAscending; public SortablePagedDataModel(int pageSize) { super(pageSize); } public final String getSortColumn() { return sortColumn; } public final void setSortColumn(String sortColumn) { this.sortColumn = sortColumn; } public final boolean isSortAscending() { return sortAscending; } public final void setSortAscending(boolean sortAscending) { this.sortAscending = sortAscending; } } Nothing too complicated heh. This is the datamodel which we will use. You will have to extend it and implement: fetchPage(int startRow, int pageSize) и int getDatasetSize(), which fetch the data page and total amount of records, accordingly.\nAs I have mentioned already, I needed to write a \u0026ldquo;custom\u0026rdquo; component. Actually not much to code:\npackage com.anydoby.jsfpager; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.faces.el.ValueBinding; import javax.faces.model.DataModel; import org.apache.myfaces.component.html.ext.HtmlDataTable; public class SortableDataTable extends HtmlDataTable { public final static String COMPONENT_TYPE = \u0026#34;com.anydoby.jsfpager.SortableDataTable\u0026#34;; private Boolean sortable; @SuppressWarnings(\u0026#34;unchecked\u0026#34;) @Override protected DataModel createDataModel() { DataModel model; boolean sortable = isSortableModel(); if (!sortable) { model = super.createDataModel(); } else { Object value = getValue(); if (value instanceof SortablePagedDataModel) { SortablePagedDataModel sortableModel = (SortablePagedDataModel) value; String sortColumn = getSortProperty(); boolean sortAscending = isSortAscending(); sortableModel.setSortAscending(sortAscending); sortableModel.setSortColumn(sortColumn); model = sortableModel; } else { throw new IllegalArgumentException( \u0026#34;If table is sortable you should provide an implementation of SortablePageDataModel as value\u0026#34;); } } return model; } public void setSortableModel(boolean sortable) { this.sortable = sortable ? Boolean.TRUE : Boolean.FALSE; } @SuppressWarnings(\u0026#34;deprecation\u0026#34;) public boolean isSortableModel() { if (this.sortable != null) return this.sortable.booleanValue(); ValueBinding vb = getValueBinding(\u0026#34;sortableModel\u0026#34;); Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null; return v != null ? v.booleanValue() : false; } @Override public Object saveState(FacesContext context) { Object[] objs = (Object[]) super.saveState(context); List\u0026lt;Object\u0026gt; list = new ArrayList\u0026lt;Object\u0026gt;(Arrays.asList(objs)); list.add(sortable); objs = list.toArray(new Object[list.size()]); return objs; } @Override public void restoreState(FacesContext context, Object state) { super.restoreState(context, state); Object[] objs = (Object[])state; sortable = (Boolean) objs[objs.length - 1]; } } The table without the sortableModel attribute will act the same as original . If sortableModel=true and the model is SortablePagedDataModel, then the sorting state is communicated to it.\nAnd finally, the tag class which binds JSP and your component:\npackage com.anydoby.jsfpager; import org.apache.myfaces.taglib.html.ext.HtmlDataTableTag; public class SortableDataTableTag extends HtmlDataTableTag { private String sortableModel; @Override public String getComponentType() { return SortableDataTable.COMPONENT_TYPE; } @Override public void release() { super.release(); sortableModel = null; } @Override protected void setProperties(UIComponent component) { super.setProperties(component); setBooleanProperty(component, \u0026#34;sortableModel\u0026#34;, sortableModel); } public String getSortableModel() { return sortableModel; } public void setSortableModel(String sortableModel) { this.sortableModel = sortableModel; } } The attachment to this article contains the complete code for the project (except for the tomahawk.jar and myfaces), tld, faces-config.xml and jsp with usage example. You can launch build.xml, first put the required jars into the lib folder and in the dist you will get a jar with component. Place it to your WEB-INF/lib, add to the classpath of your IDE and it can be used.\nIf you do not want to compile, here is the compiled jar file which I use.\nIf preserveDataModel=\u0026ldquo;false\u0026rdquo;, then fetchPage will be invoked twice the first time with start=0, and the second time with current start value, therefore I would recomment making all your model classes Serializable and setting preserveDataModel=\u0026ldquo;true\u0026rdquo;.\nFirst published on the old anydoby.com blog on 2007-10-13.\n","date":"13 October 2007","externalUrl":null,"permalink":"/articles/working-with-large-data-tables-in-jsf-paging-and-sorting/","section":"Articles","summary":"","title":"Working with large data tables in JSF - paging and sorting","type":"articles"},{"content":"Last weekend I tried to configure Tomcat to use APR library to boost performance. The build and setup went smoothly. But when I started Tomcat I got the following error:\nINFO: Loaded Apache Tomcat Native library 1.1.10. Sep 7, 2007 6:05:16 PM org.apache.catalina.core.AprLifecycleListener init INFO: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true]. Sep 7, 2007 6:05:16 PM org.apache.coyote.http11.Http11AprProtocol init SEVERE: Error initializing endpoint java.lang.Exception: Socket bind failed: [22] Invalid argument at org.apache.tomcat.util.net.AprEndpoint.init(AprEndpoint.java:612) at org.apache.coyote.http11.Http11AprProtocol.init(Http11AprProtocol.java:121) at org.apache.catalina.connector.Connector.initialize(Connector.java:1059) After several debug sessions over Tomcat\u0026rsquo;s source it appeared that the Connector\u0026rsquo;s attribute address should be set to machine\u0026rsquo;s IP. For test purposes it can be 127.0.0.1. However for the server which is connected to the internet this attribute is not neccessary. On this server Tomcat is launched without this attribute :)\nFirst published on the old anydoby.com blog on 2007-10-09.\n","date":"9 October 2007","externalUrl":null,"permalink":"/articles/error-starting-up-tomcat-with-apr/","section":"Articles","summary":"","title":"Error starting up Tomcat with APR","type":"articles"},{"content":"Once upon a time there lived a bean. Everything would be fine if it were not for changes in customer\u0026rsquo;s requirements - had to put in a couple of lines. I\u0026rsquo;ve added them, compiled, alas - Weblogic does not deploy the updated ear. Here\u0026rsquo;s the output:\n####\u0026lt;Sep 19, 2007 10:54:32 AM EEST\u0026gt; \u0026lt;Warning\u0026gt; \u0026lt;Deployer\u0026gt; \u0026lt;Szolotaryov\u0026gt; \u0026lt;tpadminServer\u0026gt; \u0026lt;[ACTIVE] ExecuteThread: \u0026#39;0\u0026#39; for queue: \u0026#39;weblogic.kernel.Default (self-tuning)\u0026#39;\u0026gt; \u0026lt;\u0026lt;WLS Kernel\u0026gt;\u0026gt; \u0026lt;\u0026gt; \u0026lt;\u0026gt; \u0026lt;1190188472905\u0026gt; \u0026lt;BEA-149078\u0026gt; \u0026lt;Stack trace for message 149004 weblogic.application.ModuleException: Exception preparing module: EJBModule(tpadmin.comp.TPMonitorCore.jar) [EJB:011023]An error occurred while reading the deployment descriptor. The error was: : java.lang.NullPointerException. at weblogic.ejb.container.deployer.EJBModule.prepare(EJBModule.java:399) at weblogic.application.internal.flow.ModuleListenerInvoker.prepare(ModuleListenerInvoker.java:93) at weblogic.application.internal.flow.DeploymentCallbackFlow$1.next(DeploymentCallbackFlow.java:360) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26) at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:56) at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:46) at weblogic.application.internal.BaseDeployment$1.next(BaseDeployment.java:615) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26) at weblogic.application.internal.BaseDeployment.prepare(BaseDeployment.java:191) at weblogic.application.internal.DeploymentStateChecker.prepare(DeploymentStateChecker.java:147) at weblogic.deploy.internal.targetserver.AppContainerInvoker.prepare(AppContainerInvoker.java:61) at weblogic.deploy.internal.targetserver.operations.ActivateOperation.createAndPrepareContainer(ActivateOperation.java:189) at weblogic.deploy.internal.targetserver.operations.ActivateOperation.doPrepare(ActivateOperation.java:87) at weblogic.deploy.internal.targetserver.operations.AbstractOperation.prepare(AbstractOperation.java:217) at weblogic.deploy.internal.targetserver.DeploymentManager.handleDeploymentPrepare(DeploymentManager.java:719) at weblogic.deploy.internal.targetserver.DeploymentManager.prepareDeploymentList(DeploymentManager.java:1186) at weblogic.deploy.internal.targetserver.DeploymentManager.handlePrepare(DeploymentManager.java:248) at weblogic.deploy.internal.targetserver.DeploymentServiceDispatcher.prepare(DeploymentServiceDispatcher.java:157) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.doPrepareCallback(DeploymentReceiverCallbackDeliverer.java:157) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.access$000(DeploymentReceiverCallbackDeliverer.java:12) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer$1.run(DeploymentReceiverCallbackDeliverer.java:45) at weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:464) at weblogic.work.ExecuteThread.execute(ExecuteThread.java:200) at weblogic.work.ExecuteThread.run(ExecuteThread.java:172) java.io.IOException: : java.lang.NullPointerException at weblogic.ejb.container.dd.xml.EjbDescriptorReaderImpl.processStandardAnnotations(EjbDescriptorReaderImpl.java:324) at weblogic.ejb.container.dd.xml.EjbDescriptorReaderImpl.createReadOnlyDescriptorFromJarFile(EjbDescriptorReaderImpl.java:186) at weblogic.ejb.spi.EjbDescriptorFactory.createReadOnlyDescriptorFromJarFile(EjbDescriptorFactory.java:93) at weblogic.ejb.container.deployer.EJBModule.loadEJBDescriptor(EJBModule.java:965) at weblogic.ejb.container.deployer.EJBModule.prepare(EJBModule.java:335) at weblogic.application.internal.flow.ModuleListenerInvoker.prepare(ModuleListenerInvoker.java:93) at weblogic.application.internal.flow.DeploymentCallbackFlow$1.next(DeploymentCallbackFlow.java:360) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26) at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:56) at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:46) at weblogic.application.internal.BaseDeployment$1.next(BaseDeployment.java:615) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26) at weblogic.application.internal.BaseDeployment.prepare(BaseDeployment.java:191) at weblogic.application.internal.DeploymentStateChecker.prepare(DeploymentStateChecker.java:147) at weblogic.deploy.internal.targetserver.AppContainerInvoker.prepare(AppContainerInvoker.java:61) at weblogic.deploy.internal.targetserver.operations.ActivateOperation.createAndPrepareContainer(ActivateOperation.java:189) at weblogic.deploy.internal.targetserver.operations.ActivateOperation.doPrepare(ActivateOperation.java:87) at weblogic.deploy.internal.targetserver.operations.AbstractOperation.prepare(AbstractOperation.java:217) at weblogic.deploy.internal.targetserver.DeploymentManager.handleDeploymentPrepare(DeploymentManager.java:719) at weblogic.deploy.internal.targetserver.DeploymentManager.prepareDeploymentList(DeploymentManager.java:1186) at weblogic.deploy.internal.targetserver.DeploymentManager.handlePrepare(DeploymentManager.java:248) at weblogic.deploy.internal.targetserver.DeploymentServiceDispatcher.prepare(DeploymentServiceDispatcher.java:157) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.doPrepareCallback(DeploymentReceiverCallbackDeliverer.java:157) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.access$000(DeploymentReceiverCallbackDeliverer.java:12) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer$1.run(DeploymentReceiverCallbackDeliverer.java:45) at weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:464) at weblogic.work.ExecuteThread.execute(ExecuteThread.java:200) at weblogic.work.ExecuteThread.run(ExecuteThread.java:172) Not really clear to you, is it? Me too. I asked around the office, it appears that several guys had this headache before, but haven\u0026rsquo;t solved this. Google answers with a couple of links - they are questions without answers. So I started digging. And here is what I dug out of this.\nAt first I tried to just remove the annotations, as weblogic\u0026rsquo;s compiler might not like them. Does not work. Extracted the modified code to a separate static method in another class - non-EBJ. Got another hit in the stomach:\n####\u0026lt;Sep 19, 2007 11:50:25 AM EEST\u0026gt; \u0026lt;Warning\u0026gt; \u0026lt;Deployer\u0026gt; \u0026lt;Szolotaryov\u0026gt; \u0026lt;tpadminServer\u0026gt; \u0026lt;[ACTIVE] ExecuteThread: \u0026#39;3\u0026#39; for queue: \u0026#39;weblogic.kernel.Default (self-tuning)\u0026#39;\u0026gt; \u0026lt;\u0026lt;WLS Kernel\u0026gt;\u0026gt; \u0026lt;\u0026gt; \u0026lt;\u0026gt; \u0026lt;1190191825249\u0026gt; \u0026lt;BEA-149004\u0026gt; \u0026lt;Failures were detected while initiating deploy task for application \u0026#39;_appsdir_tpadmin.app.TPAdmin_ear\u0026#39;.\u0026gt; ####\u0026lt;Sep 19, 2007 11:50:25 AM EEST\u0026gt; \u0026lt;Warning\u0026gt; \u0026lt;Deployer\u0026gt; \u0026lt;Szolotaryov\u0026gt; \u0026lt;tpadminServer\u0026gt; \u0026lt;[ACTIVE] ExecuteThread: \u0026#39;3\u0026#39; for queue: \u0026#39;weblogic.kernel.Default (self-tuning)\u0026#39;\u0026gt; \u0026lt;\u0026lt;WLS Kernel\u0026gt;\u0026gt; \u0026lt;\u0026gt; \u0026lt;\u0026gt; \u0026lt;1190191825249\u0026gt; \u0026lt;BEA-149078\u0026gt; \u0026lt;Stack trace for message 149004 weblogic.application.ModuleException: Exception preparing module: EJBModule(tpadmin.comp.TPMonitorCore.jar) at weblogic.ejb.container.deployer.EJBModule.prepare(EJBModule.java:399) at weblogic.application.internal.flow.ModuleListenerInvoker.prepare(ModuleListenerInvoker.java:93) at weblogic.application.internal.flow.DeploymentCallbackFlow$1.next(DeploymentCallbackFlow.java:360) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26) at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:56) at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:46) at weblogic.application.internal.BaseDeployment$1.next(BaseDeployment.java:615) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26) at weblogic.application.internal.BaseDeployment.prepare(BaseDeployment.java:191) at weblogic.application.internal.DeploymentStateChecker.prepare(DeploymentStateChecker.java:147) at weblogic.deploy.internal.targetserver.AppContainerInvoker.prepare(AppContainerInvoker.java:61) at weblogic.deploy.internal.targetserver.operations.ActivateOperation.createAndPrepareContainer(ActivateOperation.java:189) at weblogic.deploy.internal.targetserver.operations.ActivateOperation.doPrepare(ActivateOperation.java:87) at weblogic.deploy.internal.targetserver.operations.AbstractOperation.prepare(AbstractOperation.java:217) at weblogic.deploy.internal.targetserver.DeploymentManager.handleDeploymentPrepare(DeploymentManager.java:719) at weblogic.deploy.internal.targetserver.DeploymentManager.prepareDeploymentList(DeploymentManager.java:1186) at weblogic.deploy.internal.targetserver.DeploymentManager.handlePrepare(DeploymentManager.java:248) at weblogic.deploy.internal.targetserver.DeploymentServiceDispatcher.prepare(DeploymentServiceDispatcher.java:157) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.doPrepareCallback(DeploymentReceiverCallbackDeliverer.java:157) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.access$000(DeploymentReceiverCallbackDeliverer.java:12) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer$1.run(DeploymentReceiverCallbackDeliverer.java:45) at weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:464) at weblogic.work.ExecuteThread.execute(ExecuteThread.java:200) at weblogic.work.ExecuteThread.run(ExecuteThread.java:172) java.lang.StringIndexOutOfBoundsException: String index out of range: 51968 at java.lang.String.checkBounds(String.java:372) at java.lang.String.\u0026lt;init\u0026gt;(String.java:404) at serp.bytecode.lowlevel.ConstantPoolTable.readString(ConstantPoolTable.java:112) at serp.bytecode.lowlevel.ConstantPoolTable.readString(ConstantPoolTable.java:174) at org.apache.openjpa.lib.meta.ClassAnnotationMetaDataFilter.matches(ClassAnnotationMetaDataFilter.java:80) at org.apache.openjpa.lib.meta.ZipFileMetaDataIterator.hasNext(ZipFileMetaDataIterator.java:76) at org.apache.openjpa.lib.meta.ClassArgParser.mapTypeNames(ClassArgParser.java:274) at org.apache.openjpa.meta.AbstractCFMetaDataFactory.scan(AbstractCFMetaDataFactory.java:710) at org.apache.openjpa.meta.AbstractCFMetaDataFactory.parsePersistentTypeNames(AbstractCFMetaDataFactory.java:614) at org.apache.openjpa.meta.AbstractCFMetaDataFactory.getPersistentTypeNames(AbstractCFMetaDataFactory.java:578) at org.apache.openjpa.meta.MetaDataRepository.getPersistentTypeNames(MetaDataRepository.java:1187) at org.apache.openjpa.enhance.PCClassFileTransformer.\u0026lt;init\u0026gt;(PCClassFileTransformer.java:98) at org.apache.openjpa.enhance.PCClassFileTransformer.\u0026lt;init\u0026gt;(PCClassFileTransformer.java:62) at org.apache.openjpa.persistence.PersistenceProviderImpl$ClassTransformerImpl.\u0026lt;init\u0026gt;(PersistenceProviderImpl.java:143) at org.apache.openjpa.persistence.PersistenceProviderImpl$ClassTransformerImpl.\u0026lt;init\u0026gt;(PersistenceProviderImpl.java:116) at org.apache.openjpa.persistence.PersistenceProviderImpl.createContainerEntityManagerFactory(PersistenceProviderImpl.java:93) at weblogic.deployment.PersistenceUnitInfoImpl.createEntityManagerFactory(PersistenceUnitInfoImpl.java:264) at weblogic.deployment.PersistenceUnitInfoImpl.\u0026lt;init\u0026gt;(PersistenceUnitInfoImpl.java:110) at weblogic.deployment.AbstractPersistenceUnitRegistry.storeDescriptors(AbstractPersistenceUnitRegistry.java:316) at weblogic.deployment.AbstractPersistenceUnitRegistry.loadPersistenceDescriptor(AbstractPersistenceUnitRegistry.java:230) at weblogic.deployment.ModulePersistenceUnitRegistry.\u0026lt;init\u0026gt;(ModulePersistenceUnitRegistry.java:58) at weblogic.ejb.container.deployer.EJBModule.setupPersistenceUnitRegistry(EJBModule.java:185) at weblogic.ejb.container.deployer.EJBModule.prepare(EJBModule.java:331) at weblogic.application.internal.flow.ModuleListenerInvoker.prepare(ModuleListenerInvoker.java:93) at weblogic.application.internal.flow.DeploymentCallbackFlow$1.next(DeploymentCallbackFlow.java:360) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26) at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:56) at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:46) at weblogic.application.internal.BaseDeployment$1.next(BaseDeployment.java:615) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26) at weblogic.application.internal.BaseDeployment.prepare(BaseDeployment.java:191) at weblogic.application.internal.DeploymentStateChecker.prepare(DeploymentStateChecker.java:147) at weblogic.deploy.internal.targetserver.AppContainerInvoker.prepare(AppContainerInvoker.java:61) at weblogic.deploy.internal.targetserver.operations.ActivateOperation.createAndPrepareContainer(ActivateOperation.java:189) at weblogic.deploy.internal.targetserver.operations.ActivateOperation.doPrepare(ActivateOperation.java:87) at weblogic.deploy.internal.targetserver.operations.AbstractOperation.prepare(AbstractOperation.java:217) at weblogic.deploy.internal.targetserver.DeploymentManager.handleDeploymentPrepare(DeploymentManager.java:719) at weblogic.deploy.internal.targetserver.DeploymentManager.prepareDeploymentList(DeploymentManager.java:1186) at weblogic.deploy.internal.targetserver.DeploymentManager.handlePrepare(DeploymentManager.java:248) at weblogic.deploy.internal.targetserver.DeploymentServiceDispatcher.prepare(DeploymentServiceDispatcher.java:157) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.doPrepareCallback(DeploymentReceiverCallbackDeliverer.java:157) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.access$000(DeploymentReceiverCallbackDeliverer.java:12) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer$1.run(DeploymentReceiverCallbackDeliverer.java:45) at weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:464) at weblogic.work.ExecuteThread.execute(ExecuteThread.java:200) at weblogic.work.ExecuteThread.run(ExecuteThread.java:172) So the static method does not work either. I started removing lines of code one by one - to get an idea of where the hell this stuff breaks. It appeared that methods cannot be invoked at all. However you can create new objects. That was the clue to an ungraceful solution - the code, which had to be added, was placed in some object\u0026rsquo;s constructor, and in the places where the code was needed I just created that object with necessary parameters using the new operator. Oh yes, the annotations from all EJB methods should also be removed.\nGood luck :)\nFirst published on the old anydoby.com blog on 2007-09-19.\n","date":"19 September 2007","externalUrl":null,"permalink":"/articles/weird-weblogic-10-error/","section":"Articles","summary":"","title":"Weird Weblogic 10 error","type":"articles"},{"content":"It\u0026rsquo;s very simple, however iBATIS documentation does not state this. Suppose you need to issue a query with an IN (\u0026hellip;.) criterion and you need to pass an array of values into it:\n\u0026lt;select id=\u0026#34;getSmth\u0026#34; resultClass=\u0026#34;myclass\u0026#34;\u0026gt; select name, body from myclass_table where name in ( \u0026lt;iterate conjunction=\u0026#34;,\u0026#34;\u0026gt;#[]#\u0026lt;/iterate\u0026gt; ) \u0026lt;/select\u0026gt; The essential condition for success is - don\u0026rsquo;t specify the parameterClass attribute in select and don\u0026rsquo;t specify property in iterate, otherwise the query won\u0026rsquo;t work.\nFirst published on the old anydoby.com blog on 2007-09-18.\n","date":"18 September 2007","externalUrl":null,"permalink":"/articles/how-to-iterate-over-a-parameter-array-in-ibatis-sql-query/","section":"Articles","summary":"","title":"How to iterate over a parameter array in iBATIS SQL query","type":"articles"},{"content":"I guess, every programmer who ever did localization (or i18n) wonders why the creators of first computers haven\u0026rsquo;t inroduced a common character encoding once and for all. This article will discuss an approach for making url encoding/decoding transparent.\nI have noticed that for example cyrillic characters do not arrive from the web form to the server as they are - every time you need to excercise caution when dealing with anything other than ASCII, so that the characters soup %D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9 is converted to - русский.\nFor web forms using POST method everything is quite simple: browsers usually encode characters using the encoding specified in Сontent-type meta tag. Then you have to decode the characters on the server. For this purpose you can use a filter, which will set request and response encoding, for example utf-8.\nHowever, this works well only for web forms which use POST, as for the GET and links you will have to use some other approach. The problem is that the query string - the text that goes after ? in the URL, is processed by Tomcat separately, and the encoding used is ISO-\u0026hellip;., which is ASCII.\nAll in all the solution is simple - in Tomcat\u0026rsquo;s connector you have to add the attribute - useBodyEncodingForURI=\u0026ldquo;true\u0026rdquo;. Or URIEncoding, if you are sure what encoding is used for parameters. I chose the first way + a filter, and am happy now. When using the useBodyEncodingForURI the encoding used to decode request parameters is the same as used for decoding the request body - before accessing any request parameters set request encoding, eg. request.setCharacterEncoding(\u0026ldquo;utf-8\u0026rdquo;).\nHere is how the hacked Tomcat connector looks like (file server.xml):\n\u0026lt;Connector port=\u0026#34;8080\u0026#34; protocol=\u0026#34;HTTP/1.1\u0026#34; connectionTimeout=\u0026#34;20000\u0026#34; redirectPort=\u0026#34;8443\u0026#34; useBodyEncodingForURI=\u0026#34;true\u0026#34;/\u0026gt; First published on the old anydoby.com blog on 2007-09-14.\n","date":"14 September 2007","externalUrl":null,"permalink":"/articles/non-ascii-characters-in-request-parameters-for-tomcat/","section":"Articles","summary":"","title":"Non-ASCII characters in request parameters for Tomcat","type":"articles"},{"content":"Yesterday I\u0026rsquo;ve found another IE javascript mystery: you cannot name a function setActive. If you do, the method won\u0026rsquo;t ever get called. For other browsers this method name works ok.\nFirst published on the old anydoby.com blog on 2007-09-11.\n","date":"11 September 2007","externalUrl":null,"permalink":"/articles/forbidden-method-in-ie/","section":"Articles","summary":"","title":"Forbidden method in IE","type":"articles"},{"content":"Answer: implement ApplicationContextAware. Well, it\u0026rsquo;s a yes, but only in the case when the servletContext is required after all the properties are set, but what to do if you need context property during instance initialization, before any of the properties have been set?\nThe solution is quite obvious - the servlet context needs to be injected in constructor. But how? I did not find a corresponding bean to do this so I decided to create a simple facility:\npackage com.anydoby; import javax.servlet.ServletContext; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.web.context.WebApplicationContext; public class ApplicationContextHelper implements ApplicationContextAware { private WebApplicationContextctx; public void setApplicationContext(ApplicationContext ctx) throws BeansException { this.ctx = (WebApplicationContext)ctx; } public ServletContext getContext() { ServletContext servletContext = ctx.getServletContext(); return servletContext; } } This is the bean, which is being injected with the web application context. And here is the bean, which requires the servlet context:\npublic class SomeClass { public SomeClass(ServletContext ctx) { // do smth.... } } and here goes the config stuff:\n\u0026lt;bean class=\u0026#34;SomeClass\u0026#34;\u0026gt; \u0026lt;constructor-arg\u0026gt; \u0026lt;bean сlass=\u0026#34;org.springframework.beans.factory.config.MethodInvokingFactoryBean\u0026#34;\u0026gt; \u0026lt;property name=\u0026#34;targetObject\u0026#34;\u0026gt; \u0026lt;bean сlass=\u0026#34;com.anydoby.ApplicationContextHelper\u0026#34;\u0026gt;\u0026lt;/bean\u0026gt; \u0026lt;/property\u0026gt; \u0026lt;property name=\u0026#34;targetMethod\u0026#34; value=\u0026#34;getContext\u0026#34;/\u0026gt; \u0026lt;/bean\u0026gt; \u0026lt;/constructor-arg\u0026gt; \u0026lt;/bean\u0026gt; that\u0026rsquo;s all :)\nFirst published on the old anydoby.com blog on 2007-08-29.\n","date":"29 August 2007","externalUrl":null,"permalink":"/articles/how-to-access-servlet-context-before-spring-bean-s-propertie/","section":"Articles","summary":"","title":"How to access servlet context before spring bean's properties are set","type":"articles"},{"content":"I would never have thought this would work in both Firefox and IE. Open any webpage and then in the addressbar paste this line javascript:document.body.contentEditable=\u0026lsquo;true\u0026rsquo;; document.designMode=\u0026lsquo;on\u0026rsquo;; void 0 Press ENTER and you can edit any element on the page :)\nFirst published on the old anydoby.com blog on 2007-08-27.\n","date":"27 August 2007","externalUrl":null,"permalink":"/articles/editable-browser-page/","section":"Articles","summary":"","title":"Editable browser page","type":"articles"},{"content":"I\u0026rsquo;ve longed to write this article quite a long time ago, but I have not had a good example for it. Today I have it :)\nI have mapped a pojo in iBATIS:\npublic class Shop { private int id; private String name; private String addressLine; private String city; private String phones; private ShopNetwork network; private int map; map is an optional parameter, i.e. in the database its value may be null. As far as I remember, the early versions of Hibernate in this case would safely replace null with 0 in the pojo, in case of a primitive field. For certain circumstances this is not bad at all. However the correct solution is to have a field of non-primitive type wrapper, like Integer, so that null would remain null.\nThis time I was \u0026ldquo;surprised\u0026rdquo; by iBATIS throwing an NPE. The stack (largely abridged) was very strange:\ncom.ibatis.common.jdbc.exception.NestedSQLException: --- The error occurred in com/anydoby/catalog/dao/pojo/enums.xml. --- The error occurred while applying a result map. --- Check the enums.shopWithNetwork. --- The error happened while setting a property on the result object. --- Cause: net.sf.cglib.beans.BulkBeanException .... net.sf.cglib.beans.BulkBeanException com.anydoby.catalog.dao.pojo.Shop$$BulkBeanByCGLIB$$4d784893. setPropertyValues(\u0026lt;generated\u0026gt;) .... java.lang.NullPointerException com.anydoby.catalog.dao.pojo.Shop$$BulkBeanByCGLIB$$4d784893. setPropertyValues(\u0026lt;generated\u0026gt;) If I hadn\u0026rsquo;t longed to write this article long ago, I would have had quite hard time chasing the bug, but today I just replaced int with Integer and everything works nice again :)\nFirst published on the old anydoby.com blog on 2007-08-22.\n","date":"22 August 2007","externalUrl":null,"permalink":"/articles/nullpointerexception-when-accessing-primitive-fields-using-r/","section":"Articles","summary":"","title":"NullPointerException when accessing primitive fields using reflection","type":"articles"},{"content":"Today I have decided not to use the SYSDBA account for database creation and management. Created a user and then created the database using isql. Created a couple of tables in it. Logged out and tried to connect to the db from another machine. And haven\u0026rsquo;t succedeed.\nI get an error GDS 335544344. Tried all possible solutions: created the same database as SYSDBA, tried to connect to the database using SYSDBA account, and then I suddenly realized - the server is linux hosted:\nchown firebird:firebird mydatabase.fdb That\u0026rsquo;s the solution: I created the database under root account, but firebird tries to read it using its own user account - firebird.\nFirst published on the old anydoby.com blog on 2007-08-10.\n","date":"10 August 2007","externalUrl":null,"permalink":"/articles/firebird-error-335544344/","section":"Articles","summary":"","title":"Firebird error 335544344","type":"articles"},{"content":"Today I stumbled upon another bug in Weblogic. Its EJB compiler goes nuts, if your EJB implements a method with varargs parameter. The error has a quite strange stacktrace (though it\u0026rsquo;s usual for Weblogic):\njava.io.IOException: Compiler failed executable.exec: D:/wl-domain/servers/tpadminServer/cache/ EJBCompilerCache/-dlel6hz0tfi7/.../ejb/session/ dao/....Bean_ggrd50_....Impl.java:33: modifier transient not allowed here The solution is simple - replace varargs with a regular array parameter.\nFirst published on the old anydoby.com blog on 2007-07-12.\n","date":"12 July 2007","externalUrl":null,"permalink":"/articles/modifier-transient-not-allowed-here-in-weblogic-10/","section":"Articles","summary":"","title":"modifier transient not allowed here in Weblogic 10","type":"articles"},{"content":"Today I tried to deploy my webapp onto JBoss app server and stumbled upon this error/bug/issue :(\nIt appears that JBoss is the first one who gets to configure Log4j configuration and if you try to configure it somehow later, the Log4j goes crazy and the app cannot be deployed.\nWell, what else could I do? I had to turn of Log4j configuration (I was using Spring\u0026rsquo;s org.springframework.web.util.Log4jConfigListener for this purpose) for the time being.\nAs far as I\u0026rsquo;m concerned JBoss\u0026rsquo;s log4j configuration is managed through an xml config located in conf/jboss-log4j.xml, which is the place where one can configure his application\u0026rsquo;s logging.\nFirst published on the old anydoby.com blog on 2007-07-07.\n","date":"7 July 2007","externalUrl":null,"permalink":"/articles/error-invalid-console-appender-config-detected-console-strea/","section":"Articles","summary":"","title":"ERROR: invalid console appender config detected, console stream is looping","type":"articles"},{"content":"I understand that performance comparison of \u0026ldquo;low-level\u0026rdquo; vs \u0026ldquo;high-level\u0026rdquo; technologies is rather unfair, but I will, as I\u0026rsquo;ve been astonished with how much performance we sacrifice to rapid development using JPA and JSF.\nOur team has got a task of making a web page where one could browse through up to 10000 database records simultaneously. We failed to convince our customer that he simply does not need that much on one page. We offered various paging/filtering solutions which would display more specific information, but the customer wanted just that - all 10000 records on one page. Ok we said, let\u0026rsquo;s do it. Here I\u0026rsquo;ll describe what we came up with.\nThe first solution was straightforward. We used JPA and JSF. Under Weblogic 10 JPA implementation is Kodo (or OpenJPA). The page which was to display the results, contained one big table of 5-6 columns, and the data displayed belonged to 2 separate tables. JPA suggests using EAGER and LAZY fetch strategies for injecting entity dependencies. LAZY is not our choise as we need all the records at once. As for the EAGER fetch, it appeared to be a simple select. It means that after selecting 10000 records we have 10000 more selects - one per each record to select its child. This is what I disliked about JPA most of all, Hibernate for example, has a JOIN fetch type, which allows the framework to generate a select with a join to fetch child entity.\nThe table was rendered using JSF , sorting was implemented by hand, because sorting 10000 records in memory (which the component does), performs poorly. At last we have made it, measured throughput with JMeter - the system handles up to 30 requests per minute. When the number of users grows to 3 and over the server crashes with OutOfMemory exception. And that\u0026rsquo;s no wonder :) tons of redundant objects are generated all over the way - both in persistence and presentation layer, and they cannot be garbage collected until the request is completely rendered. All in all the customer was quite surprised with performance and we have got an optimization task. At first we suspected that JPA was the bottleneck. More specifically, we suspected that 10000 subselects were the problem. I rewrote the select using native sql query with explicit join and used @SqlResultSetMapping to map sql resultset to pojos. A very useful feature, which makes JPA not a pure ORM tool, but also a sort of resultset mapper, much like iBATIS (though iBATIS is much simpler and performant). Then we measured performance again. Pure performance gain on persistence layer was about 15%, not much. Then we started profiling JSF, and it appeared that this beast eats his lion\u0026rsquo;s share of CPU and memory. We have decided to place the table inside an iframe, the results would be rendered by a JSP page. Select is performed using pure JDBC/SQL. The controller - the servlet - handles request parameters like sorting columns, filter parameters, etc. makes a query and puts the results Iterator to requestScope, which allows iterating the resultset in an OOP fashion - returning a POJO for each row. The object instance returned is always the same, it is just filled with new data every time the next object is requested. By using this little trick we managed to avoid GC pauses - no extra objects were created during query processing. After quering the database a JSP is included in request (I used JSTL, to avoid scriptlets), connection to the database is closed when the result has been completely rendered. The results exceeded our expectations. Performance gain achieved was more than 20 times! We even did not measure memory consumption gains, as they were obvious. I must admit that complexity of the solution has increased, however MVC pattern was preserved, - we used controller (servlet), model (though it was tied to persistence layer), and view (JSP page). But the result was worth the trouble. Afterwards we redesigned another heavy part of the application also using servlet/jsp/jdbc, the rest was left as it was, for small amounts of data JPA/JSF work reasonably fast and complex form processing is really simpler. But in case you need to display something very big and do it fast, the old school JSPs + JDBC are still the best choice.\nFirst published on the old anydoby.com blog on 2007-07-06.\n","date":"6 July 2007","externalUrl":null,"permalink":"/articles/performance-comparison-jsp-jdbc-vs-jsf-jpa/","section":"Articles","summary":"","title":"Performance comparison: JSP + JDBC vs JSF + JPA","type":"articles"},{"content":"Today is the great day - I finally managed to subscribe to a VPS hosting plan, which can be used to install and run anything. And the most important - it will have no php, mysql or apache :) I have spent a year sharing the server with a guy who wanted to use php, and I had to tune Tomcat to use Apache redirectors, url rewriters etc., because every week the server would crash for no reason. Today I have got my own sandbox which I can use to launch Tomcat on the 80-th port.\nSo welcome, to visit me. Hope this site will be updated more frequently and will not be down all the time.\nFirst published on the old anydoby.com blog on 2007-07-05.\n","date":"5 July 2007","externalUrl":null,"permalink":"/articles/my-own-server/","section":"Articles","summary":"","title":"My own server","type":"articles"},{"content":"A couple of weeks ago I\u0026rsquo;ve stumbled upon a problem of integrating Tiles and Velocity under Spring MVC. It appears that there is no out-of-the-box solution to this. Tiles can be used in Velocity through the Velocity Tools, but not under Spring. The reason why I needed this integration is because of advanced templating features of Tiles - template inheritance, for instance, and featured of Velocity - ease of use and high performance as compared to JSP/JSTL.\nSo here is the solution.\nI assume that all templates and resources are placed in the WEB-INF directory.\nCreate a Velocity template, which will be the placeholder for your tiles (WEB-INF/layouts/template.vm):\n\u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; #parse($tiles.getAttribute(\u0026#34;header\u0026#34;)) #parse($tiles.getAttribute(\u0026#34;central\u0026#34;)) #parse($tiles.getAttribute(\u0026#34;bottom\u0026#34;)) \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; The header, central and bottom are the names of the tiles attributes we will be inserting.\nThe tiles definition file (tiles-defs.xml) looks like this:\n\u0026lt;!DOCTYPE tiles-definitions PUBLIC \u0026#34;-//Apache Software Foundation//DTD Tiles Configuration 1.3//EN\u0026#34; \u0026#34;http://struts.apache.org/dtds/tiles-config_1_3.dtd\u0026#34;\u0026gt; \u0026lt;tiles-definitions\u0026gt; \u0026lt;definition name=\u0026#34;main_base\u0026#34; page=\u0026#34;/layouts/template.vm\u0026#34;\u0026gt; \u0026lt;put name=\u0026#34;header\u0026#34; value=\u0026#34;/layouts/header.vm\u0026#34; /\u0026gt; \u0026lt;/definition\u0026gt; \u0026lt;definition name=\u0026#34;page.tile\u0026#34; extends=\u0026#34;main_base\u0026#34;\u0026gt; \u0026lt;put name=\u0026#34;central\u0026#34; value=\u0026#34;messages.vm\u0026#34; /\u0026gt; \u0026lt;/definition\u0026gt; \u0026lt;/tiles-definitions\u0026gt;\nThen goes the Spring configuration:\nFor tiles bean\n\u0026lt;bean id=\u0026#34;tilesConfigurer\u0026#34; class=\u0026#34;org.springframework.web.servlet.view.tiles.TilesConfigurer\u0026#34;\u0026gt; \u0026lt;property name=\u0026#34;factoryClass\u0026#34; value=\u0026#34;org.apache.struts.tiles.xmlDefinition.I18nFactorySet\u0026#34;/\u0026gt; \u0026lt;property name=\u0026#34;definitions\u0026#34;\u0026gt; \u0026lt;list\u0026gt; \u0026lt;value\u0026gt;/WEB-INF/config/tiles-defs.xml\u0026lt;/value\u0026gt; \u0026lt;/list\u0026gt; \u0026lt;/property\u0026gt; \u0026lt;/bean\u0026gt; For the velocity view resolver and engine\n\u0026lt;bean id=\u0026#34;velocityConfig\u0026#34; class=\u0026#34;org.springframework.web.servlet.view.velocity.VelocityConfigurer\u0026#34;\u0026gt; \u0026lt;property name=\u0026#34;resourceLoaderPath\u0026#34; value=\u0026#34;/WEB-INF/views\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;velocityProperties\u0026#34;\u0026gt; \u0026lt;props\u0026gt; \u0026lt;prop key=\u0026#34;input.encoding\u0026#34;\u0026gt;utf-8\u0026lt;/prop\u0026gt; \u0026lt;prop key=\u0026#34;output.encoding\u0026#34;\u0026gt;utf-8\u0026lt;/prop\u0026gt; \u0026lt;/props\u0026gt; \u0026lt;/property\u0026gt; \u0026lt;/bean\u0026gt; \u0026lt;bean id=\u0026#34;viewResolver\u0026#34; class=\u0026#34;org.springframework.web.servlet.view.velocity.VelocityViewResolver\u0026#34;\u0026gt; \u0026lt;property name=\u0026#34;cache\u0026#34; value=\u0026#34;true\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;prefix\u0026#34; value=\u0026#34;\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;exposeSpringMacroHelpers\u0026#34; value=\u0026#34;true\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;order\u0026#34; value=\u0026#34;1\u0026#34;\u0026gt;\u0026lt;/property\u0026gt; \u0026lt;property name=\u0026#34;contentType\u0026#34; value=\u0026#34;text/html; charset=utf-8\u0026#34;\u0026gt;\u0026lt;/property\u0026gt; \u0026lt;property name=\u0026#34;toolboxConfigLocation\u0026#34; value=\u0026#34;WEB-INF/config/velocity-toolbox.xml\u0026#34;\u0026gt;\u0026lt;/property\u0026gt; \u0026lt;property name=\u0026#34;suffix\u0026#34; value=\u0026#34;.tile\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;viewClass\u0026#34; value=\u0026#34;com.yoursite.VelocityTilesView\u0026#34; /\u0026gt; \u0026lt;/bean\u0026gt; Don\u0026rsquo;t forget to create Velocity tools config:\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34;?\u0026gt; \u0026lt;toolbox\u0026gt; \u0026lt;tool\u0026gt; \u0026lt;key\u0026gt;tiles\u0026lt;/key\u0026gt; \u0026lt;scope\u0026gt;request\u0026lt;/scope\u0026gt; \u0026lt;class\u0026gt;org.apache.velocity.tools.struts.TilesTool\u0026lt;/class\u0026gt; \u0026lt;/tool\u0026gt; \u0026lt;/toolbox\u0026gt; And finally create a custom view class, which will actually do the job of interpreting the Velocity/Tiles templates:\npackage com.yoursite; import java.util.Map; import javax.servlet.*; import javax.servlet.http.*; import org.apache.struts.tiles.*; import org.apache.velocity.context.Context; import org.springframework.context.ApplicationContextException; import org.springframework.web.servlet.view.velocity.VelocityToolboxView; import org.springframework.web.util.WebUtils; public class VelocityTilesView extends VelocityToolboxView { /** * Name of the attribute that will override the path of the layout page to render. A Tiles * component controller can set such an attribute to dynamically switch the look and feel of a * Tiles page. * * @see #setPath */ public static final String PATH_ATTRIBUTE = VelocityTilesView.class.getName() + \u0026#34;.PATH\u0026#34;; private DefinitionsFactory definitionsFactory; /** * Constructor for use as a bean. */ public VelocityTilesView() {} /** * Create a new InternalResourceView with the given URL. */ public VelocityTilesView(String url) { setUrl(url); } /** * Render the internal resource given the specified model. This includes setting the model as * request attributes. */ protected void renderMergedTemplateModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { exposeHelpers(model, request); Context velocityContext = createVelocityContext(model, request, response); exposeHelpers(velocityContext, request, response); exposeToolAttributes(velocityContext, request); exposeModelAsRequestAttributes(model, request); String tile = prepareForRendering(request, response); mergeTemplate(getTemplate(tile), velocityContext, response); } /** * Determine whether to use RequestDispatcher\u0026#39;s \u0026lt;code\u0026gt;include\u0026lt;/code\u0026gt; or \u0026lt;code\u0026gt;forward\u0026lt;/code\u0026gt; * method. * \u0026lt;p\u0026gt; * Performs a check whether an include URI attribute is found in the request, indicating an * include request, and whether the response has already been committed. In both cases, an * include will be performed, as a forward is not possible anymore. */ protected boolean useInclude(HttpServletRequest request, HttpServletResponse response) { return (WebUtils.isIncludeRequest(request) || response.isCommitted()); } /** * Expose the current request URI and paths as {@link HttpServletRequest} attributes under the * keys defined in the Servlet 2.4 specification, for Servlet 2.3-containers. * \u0026lt;p\u0026gt; * Does not override values if already present, to not conflict with Servlet 2.4+ containers. */ protected void exposeForwardRequestAttributes(HttpServletRequest request) { WebUtils.exposeForwardRequestAttributes(request); } /** * Overrides checkTemplate in VelocityView to avoid throwing an exception if it can\u0026#39;t find a * file. */ protected void checkTemplate() throws ApplicationContextException { // skip check. } /** * Set the path of the layout page to render. */ public static void setPath(HttpServletRequest request, String path) { request.setAttribute(PATH_ATTRIBUTE, path); } protected void initApplicationContext() throws ApplicationContextException { super.initApplicationContext(); // get definitions factory this.definitionsFactory = (DefinitionsFactory) getServletContext().getAttribute( TilesUtilImpl.DEFINITIONS_FACTORY); if (this.definitionsFactory == null) { throw new ApplicationContextException( \u0026#34;Tiles definitions factory not found: TilesConfigurer not defined?\u0026#34;); } } /** * Prepare for rendering the Tiles definition: Execute the associated component controller if * any, and determine the request dispatcher path. */ protected String prepareForRendering(HttpServletRequest request, HttpServletResponse response) throws Exception { // get component definition ComponentDefinition definition = getComponentDefinition(this.definitionsFactory, request); if (definition == null) { throw new ServletException(\u0026#34;No Tiles definition found for name \u0026#39;\u0026#34; + getUrl() + \u0026#34;\u0026#39;\u0026#34;); } // get current component context ComponentContext context = getComponentContext(definition, request); // execute component controller associated with definition, if any Controller controller = getController(definition, request); if (controller != null) { if (logger.isDebugEnabled()) { logger.debug(\u0026#34;Executing Tiles controller [\u0026#34; + controller + \u0026#34;]\u0026#34;); } executeController(controller, context, request, response); } // determine the path of the definition String path = getDispatcherPath(definition, request); if (path == null) { throw new ServletException(\u0026#34;Could not determine a path for Tiles definition \u0026#39;\u0026#34; + definition.getName() + \u0026#34;\u0026#39;\u0026#34;); } return path; } /** * Determine the Tiles component definition for the given Tiles definitions factory. */ protected ComponentDefinition getComponentDefinition(DefinitionsFactory factory, HttpServletRequest request) throws Exception { return factory.getDefinition(getUrl(), request, getServletContext()); } /** * Determine the Tiles component context for the given Tiles definition. */ protected ComponentContext getComponentContext(ComponentDefinition definition, HttpServletRequest request) throws Exception { ComponentContext context = ComponentContext.getContext(request); if (context == null) { context = new ComponentContext(definition.getAttributes()); ComponentContext.setContext(context, request); } else { context.addMissing(definition.getAttributes()); } return context; } /** * Determine and initialize the Tiles component controller for the given Tiles definition, if * any. */ protected Controller getController(ComponentDefinition definition, HttpServletRequest request) throws Exception { return definition.getOrCreateController(); } /** * Execute the given Tiles controller. */ protected void executeController(Controller controller, ComponentContext context, HttpServletRequest request, HttpServletResponse response) throws Exception { controller.execute(context, request, response, getServletContext()); } /** * Determine the dispatcher path for the given Tiles definition, i.e. the request dispatcher * path of the layout page. */ protected String getDispatcherPath(ComponentDefinition definition, HttpServletRequest request) throws Exception { Object pathAttr = request.getAttribute(PATH_ATTRIBUTE); return (pathAttr != null ? pathAttr.toString() : definition.getPath()); } } Basically this is it. You can now create a ModelAndView instance with the view set to page to display the template defined earlier in the tiles-defs.xml.\nPS: recently a new version of Tiles has been released, it is finally decoupled from Struts. I wrote a plugin which integrates Spring MVC, Velocity and now Tiles 2 - welcome here.\nFirst published on the old anydoby.com blog on 2007-06-11.\n","date":"11 June 2007","externalUrl":null,"permalink":"/articles/integrating-spring-velocity-tiles/","section":"Articles","summary":"","title":"Integrating: Spring + Velocity + Tiles","type":"articles"},{"content":"Rather annoying:\nicon = new ImageIcon(); JLabel label = new JLabel(icon); scrollPane = new JScrollPane(label, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); add(scrollPane, CENTER); the scrollpane has a zero size component. Then if you later set an image to the ImageIcon, the scrollbars do not appear.\nTo overcome this - call scrollPane.revalidate() after updating the pane\u0026rsquo;s contents in order to get up-to-date scrollbar sizes.\nFirst published on the old anydoby.com blog on 2007-05-16.\n","date":"16 May 2007","externalUrl":null,"permalink":"/articles/jscrollpane-does-not-show-scrollbars-if-child-components-are/","section":"Articles","summary":"","title":"JScrollPane does not show scrollbars if child components are resized","type":"articles"},{"content":"Today I\u0026rsquo;ve noticed a nasty \u0026ldquo;feature\u0026rdquo; of MyFaces JSF implementation: it does not invoke custom validators on fields with no user entry.\nHere\u0026rsquo;s the code from UIInput which causes the \u0026ldquo;feature\u0026rdquo;:\nprotected void validateValue(FacesContext context,Object convertedValue) { boolean empty = convertedValue == null || (convertedValue instanceof String \u0026amp;\u0026amp; ((String)convertedValue).length() == 0); if (isRequired() \u0026amp;\u0026amp; empty) { _MessageUtils.addErrorMessage(context, this, REQUIRED_MESSAGE_ID,new Object[]{getId()}); setValid(false); return; } if (!empty) { _ComponentUtils.callValidators(context, this, convertedValue); } } This means that you cannot use a custom validator to add a pretty message when the field is empty. Custom validators are only evaluated when the message is not empty. And if the value is empty it can be validated only by default validator (crap) with default error message.\nThe only resort to work around about this feature I found was to employ custom validation in action/actionListener code :(\nFirst published on the old anydoby.com blog on 2007-05-11.\n","date":"11 May 2007","externalUrl":null,"permalink":"/articles/myfaces-does-not-invoke-validators-for-empty-fields/","section":"Articles","summary":"","title":"MyFaces does not invoke validators for empty fields","type":"articles"},{"content":"Today we\u0026rsquo;ve spent the whole day trying to migrate our web application from Weblogic 9.2 to version 10. Nothing special, one would think, if it were not for the problems with getting Toplink running under Weblogic 10. Have you ever seen such a stacktrace?\njava.lang.IllegalArgumentException: URI is not hierarchical at java.io.File.\u0026lt;init\u0026gt;(File.java:335) at oracle.toplink.essentials.ejb.cmp3.persistence.ArchiveFactoryImpl.cre ateArchive(ArchiveFactoryImpl.java:85) at oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataProcesso r.readStandardMappingFiles(MetadataProcessor.java:358) at oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataProcesso r.readMappingFiles(MetadataProcessor.java:339) at oracle.toplink.essentials.ejb.cmp3.persistence.PersistenceUnitProcess or.processORMetadata(PersistenceUnitProcessor.java:344) Truncated. see log file for complete stacktrace I\u0026rsquo;ve been searching for the clue for the whole day. It appears that both Weblogic and Toplink are the guilty. Here\u0026rsquo;s the code excerpt which throws an exception:\npublic Archive createArchive(URL url) throws URISyntaxException, IOException { logger.entering(\u0026#34;ArchiveFactoryImpl\u0026#34;, \u0026#34;createArchive\u0026#34;, new Object[]{url}); Archive result; String protocol = url.getProtocol(); logger.logp(Level.FINER, \u0026#34;ArchiveFactoryImpl\u0026#34;, \u0026#34;createArchive\u0026#34;, \u0026#34;protocol = {0}\u0026#34;, protocol); if (\u0026#34;file\u0026#34;.equals(protocol)) { URI uri = null; try { // Attempt to use url.toURI since it will deal with all urls // without special characters and URISyntaxException allows us // to catch issues with special characters. This will handle // URLs that already have special characters replaced such as // URLS derived from searches for persistence.xml on the Java // System class loader uri = url.toURI(); } catch (URISyntaxException exception) { // Use multi-argument constructor for URI since single-argument // constructor and URL.toURI() do not deal with special // characters in path uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), null); } File f = new File(uri); When an attempt is made to create a file from the URI, an exception is thrown. So why are there no exceptions under Weblogic 9? The thing is that under Weblogic 9 this branch of code is never executed, because the url parameter has the protocol zip and a simple ULRArchive is created, which reads from the jar, but under Weblogic 10 this method is executed with url with protocol file, which causes problem.\nAfter quite a while of digging into Toplink\u0026rsquo;s code (thank god it\u0026rsquo;s opensource), I figured out that under Weblogic 9 Toplink creates and uses native implementation of javax.persistence.spi.PersistenceUnitInfo (SEPersistenceUnitInfo), as there is no JPA support built into the application server. And the method getJarFileUrls() returns urls with the \u0026ldquo;right\u0026rdquo; protocol - zip. However Weblogic 10 is a JEE5 compliant container, which provides its own JPA implementation - Kodo. Thus Toplink is fed with container\u0026rsquo;s own implementation of javax.persistence.spi.PersistenceUnitInfo. This implementation\u0026rsquo;s getJarFileUrls() method returns urls with protocol file :(, after which toplink\u0026rsquo;s PersistenceProvider goes crazy.\nSo, how do I solve the problem? If you urgently need a fix, just delete the branch if (\u0026ldquo;file\u0026rdquo;.equals(protocol)) and replace the ArchiveFactoryImpl with your own version. As did I. But of course this is not a solution for the long term, a bug should be posted to glassfish. Wich I will eventually do.\nPS. This solution is of course not applicable to production environments as you know why. This is why we have decided to completely abandon Toplink Essentials. Just remove the node from persistence.xml - now Kodo is used by default. By the way transition from Toplink to Kodo did not take long (thanks to JPA). I spent an overall 2 hours fixing minor incompatibilities, related mostly to more strict typing conventions in Kodo as compared to Toplink. However I must admit that I did not notice any sharp difference in operation or performance between Toplink and Kodo. Time will tell of course :)\nFirst published on the old anydoby.com blog on 2007-04-27.\n","date":"27 April 2007","externalUrl":null,"permalink":"/articles/toplink-essentials-on-weblogic-10/","section":"Articles","summary":"","title":"Toplink Essentials on Weblogic 10","type":"articles"},{"content":"Recently I\u0026rsquo;ve bought a new laptop. One of the main search criteria were: no noise, matt display and of course no \u0026ldquo;microsoft tax\u0026rdquo;.\nIt was hard to find, but finally I came up with the model. Though I had to upgrade RAM just as I bought it - up to 2 gib, just to feel comfortable. The laptop shipped with FreeDOS, which I of course changed to Ubuntu Edgy 64 bit.\nEdgy was hard to install. I don\u0026rsquo;t know why it was going this was, as my previous laptop had no problems with installation. But nx7400 just didn\u0026rsquo;t want Edgy, it seemed. It just hung all the time. I even started suspecting that something was wrong with the hardware.\nI finally installed Edgy from the third attempt.\nThe first thing which upset me was the lack of hibernate and suspend to RAM. Well, actually they exist, but do not work properly. The laptop freezes and the only way to wake it is to turn it off completely.\nThe second annoyance (already fixed in Feisty) was the followign: when I unplugged/plugged the cable or changed screen brightness the laptop hung dead.\nThe solution was relatively easy to find in the ubuntu launchpad: bug 65027 you have to add the following word in the grub config /boot/grub/menu.ls\ntitle Ubuntu, kernel 2.6.17-10-generic root (hd0,1) kernel /boot/vmlinuz-2.6.17-10-generic root=/dev/sda2 ro splash notsc nmi_watchdog=0 and also add blacklist video into /etc/modprobe.d/blacklist\nsudo echo \u0026#34;blacklist video\u0026#34; \u0026gt;\u0026gt; /etc/modprobe.d/blacklist After this \u0026ldquo;fix\u0026rdquo; my laptop stopped freezing :)\nAnd yet another problem - Edgy does not recognize Broadcom WiFi adapter out of the box. They say that nx7400\u0026rsquo;s with built-in Intel wireless are more lucky - it has opensource drivers for that gadget.\nApril 19 the Ubuntu Feisty was released. And that same date I\u0026rsquo;ve downloaded the 32-bit version and installed it onto my laptop. Frankly speaking the installation was rather dull as compared to Edgy: everything (even the Broadcom adapter) was installed automatically.\nThe Edgy fix, which I have mentioned above, is not necessary anymore. Moreover when I tried to apply it the system does not boot, so I had to roll it back :) everything just works. Though suspend to RAM still does not work. Hope the next release of Ubuntu will fix that.\nOverall feeling about Ubuntu Feisty is much better than those previous versions: I must admit that the installation utility did all the job for me. Just install it and start working.\nPS. Oh, I forgot to mention that the first Ubuntu I\u0026rsquo;ve installed was 64 bit. I had a lot of little problems with that: firstly - many packages have not yet been ported to 64 bit and you have to use \u0026ndash;force-architecture to install 32-bit apps, which does not always help. For example, Opera does not work (built-in Firefox is not my favorite browser). And yet quite a few hardware gadgets, like winmodem, have only close source 32-bit drivers. All in all I have decided to use 32-bit Feisty for the time being, until most problems are resolved.\nFirst published on the old anydoby.com blog on 2007-04-24.\n","date":"24 April 2007","externalUrl":null,"permalink":"/articles/ubuntu-on-hp-nx7400/","section":"Articles","summary":"","title":"Ubuntu on HP nx7400","type":"articles"},{"content":" I\u0026rsquo;ve been writing software for more than twenty years. Some of the tools I\u0026rsquo;ve fought with are ancient, some are bleeding edge — and I keep learning, so the list keeps growing. 20+\nYears of Java\nSince 2005, Kyiv → the Netherlands. 4\nSun certifications\nProgrammer, Developer, Web \u0026amp; Business Component. 1 / 70\nVendor award\nInspirational Vendor Award, out of 70 nominees. The campaigns # Software Engineer — freelance 2026 – now Booking.com, Amsterdam As any Software Engineer at Booking I am responsible for everything around a living service. And being a contractor I get the trickest tasks nobody wants to work on. These include: maintaining and fixing issues in .... Perl monolith on a baremetal cluster, Python data loaders in Spark, fixing / adding / removing component dependencies, configuring and optimizing APIgee routes in GCP, hardening security for external API's, optimizing metrics cardinality to save costs, looking into cache efficiency and GC pauses in a Java backend and hundreds of other tiny things. And obviously taming a fleet of AI agents 🤖️🤖️🤖️ Team lead — freelance 2025 – 2026 CJIB, Leeuwarden Migrating a Eureca/Metis system to a new Spring / Angular stack and adding features along the way. At its heart: an in-house process engine — a state machine on a database, with JMS as the messaging backbone. I worked on the architecture and the development process with the team, plus the maintenance, operations and monitoring that keep a system like that alive. Java DevOps — freelance 2020 – 2025 FedEx, Hoofddorp Started as the only back-end developer on a new global customer-registration platform and wrote its first code. Spring Boot on Azure, a validation and rules engine for each market's quirks (tax IDs, document uploads, Salesforce notifications), legacy SOAP/EJB/mainframe systems wrapped in modern REST APIs, and a CI/CD pipeline for every service. Won the Inspirational Vendor Award — chosen from 70 nominees, and the first time it went to a freelancer. Java DevOps — freelance 2019 – 2020 ING, Leeuwarden Rewrote the XLetter template-management system: Polymer/Redux front end replacing JSP, Spring Boot replacing WebSphere. Selenium tests on ING's grid, integration tests and a mock server in Kotlin. Java DevOps engineer — freelance 2018 – 2019 Bol.com, Utrecht Split a monolithic recommendations backend into microservices and moved it from the datacenter to Google Cloud: gRPC/REST services on Kubernetes, Datastore, Spinnaker, Dataflow (Apache Beam) data loaders, Prometheus and Gatling. Everything automated and in source control. Dev engineer — freelance 2017 – 2018 ING, Amsterdam Middleware and reporting for ING's pricing solution: Apache Ignite as the data layer, gRPC on top, OSGi (Karaf), ActiveMQ, Tibco and Protocol Buffers. Technical lead 2009 – 2017 Asset Control, Beetsterzwaag Eight years of integration middleware that let customers consume data from a legacy backend in every format imaginable — Camel, Spring, AspectJ, CXF, Jetty. Finished with an Akka-based scheduling and orchestration system tying the product suite together. Java architect 2007 – 2009 Mirasoft, Kyiv Replaced a huge Swing front end with IceFaces (JSF) and Spring MVC, still talking to the original EJB backend. On the side: a Groupon-style platform for the Indian market (Spring MVC, Hibernate, Lucene). Senior Java developer 2005 – 2007 Ciklum \u0026amp; Luxoft, Kyiv Trade monitoring for Deutsche Bank (JSF, JPA, WebLogic). Before that, a mobile SMS communications and advertising platform built with Spring, Struts and Eclipse RCP. First blood 2004 – 2005 Mirasoft, Kyiv Web services that combined hotel, ticket, taxi and insurance providers into one product. SOAP, REST, Tomcat — and Firebird, which later ran the first version of this site on a Raspberry Pi 1. BSc Physics 1999 – 2005 National University of Kyiv-Mohyla Academy The arsenal # Java EE, SE, ME, OSGi · Spring / Spring Boot · Camel · Akka · JPA / Hibernate · Kotlin · Groovy\nCloud \u0026amp; ops Azure · Google Cloud · Kubernetes · Docker · Spinnaker · GitLab CI · GitHub Actions · Jenkins\nFront end Angular · TypeScript · Polymer / lit-html · GWT · Vaadin · JSF\nMessaging \u0026amp; data JMS / ActiveMQ · Azure Event Hubs · gRPC · Cassandra · Apache Ignite · Oracle · Postgres · Firebird\nDesktop Eclipse RCP · SWT / JFace · Swing · JavaFX\nSpoken English · Dutch · Ukrainian · Russian\nWhat others say # Sergey is my go-to person for both front-end and back-end development of all our apps. Someone with sharp insight, lots of experience and up-to-date knowledge of the latest tech stack.\n— IT manager at FedEx, in Spilberg\u0026rsquo;s interview (translated from Dutch)\nHe built the whole prototype in a short amount of time and the quality was excellent. I later used him for 3 more projects and every time he has gone above and beyond what is required.\n— Omair Aasim, client\n","externalUrl":null,"permalink":"/about/","section":"Home","summary":"","title":"A warrior's history","type":"page"},{"content":"Questions about a plugin or an article? Maybe you have an interesting project? Send a message.\nName Email Message Send ","externalUrl":null,"permalink":"/contact/","section":"Home","summary":"","title":"Contact","type":"page"}]