AngularJS formatter/parser is (not) type sensitive

I have a small AngularJS (1.x) directive so my input field does not show the value the is in the model, but formats it before (and parses the user input from the input field’s format):

angular.module('appModule')
       .directive('fooformat', function() {

    function parse(formattedValue) {
        return formattedValue.replace('foo', '');
    }

    function format(value) {
        return value + "foo";
    }

    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attr, ngModel) {
            ngModel.$parsers.push(parse);
            ngModel.$formatters.push(format);
        }
    };
});

This does not seem to work, the fields always get empty, even though that debugging shows that the conversions are done as expected. E.g. for the string "1" the return value would become "1foo".

What seems to work is, if the changes are numerical. E.g.:

function parse(formattedValue) {
    return formattedValue - 1;
}

function format(value) {
    return value + 1;
}

This would format "1" as 2, and suddenly it would work.

Well, it’s not AngularJS formatter/parser which is sensitive to the types, but the HTML5 input field where I use it:

<input fooformat type="number ng-model="" />

needs to be changed to

<input fooformat type="text" ng-model="foo" />

Cherry-picking changes from a file to a different file

I have a file.
I have another file on a different path on a different branch with mostly the same content.
I have changes in my first file.
I want to move these changes to my second file.
The files have the same name, only the path differs.
(I also need to ignore changes in whitespace, because consistency.)

Solution:

git show SHA_HASH --relative=original/path/ -- original//path/file.name | git apply --directory=new/path/ --ignore-space-change -

Using Selenium with a virtual framebuffer

I needed to run my Selenium tests on a virtual machine, on RedHat Enterprise Linux 6.6 in a multi-screen environment and this messed up the screenshots that the tests took. Virtual frame buffer to the rescue:

First I had to install it,

wget http://vault.centos.org/6.2/os/x86_64/Packages/xorg-x11-server-Xvfb-1.10.4-6.el6.x86_64.rpm

sudo yum localinstall xorg-x11-server-Xvfb-1.10.4-6.el6.x86_64.rpm 

then I could start it,

Xvfb :1 -screen 5 1024x768x8 &

make that terminal session use it,

export DISPLAY=:1.5

and I could finally run my tests, with the screenshots working fine.

Oracle and empty strings

Still as a reminder to myself in case some rows are missing from a query…

Oracle stores empty strings as NULL. So far I’m good, everybody’s aware of that, I think that I know everything. Then suddenly a query doesn’t return all the values I expect from it and I wonder why.

For example if I have the query

SELECT * FROM FOO WHERE BAR <> '';

I may expect it to return every row where BAR isn’t an empty string. Or in Oracle’s case a NULL. Well, too bad, because an empty string isn’t NULL. So any row where BAR is NULL will be ignored and won’t be in the resultset. I have to get rows like that with

SELECT * FROM FOO WHERE BAR IS NOT NULL;

But there is more. Let’s see the next query:

SELECT * FROM FOO WHERE BAR <> 'A';

What does this do? Gets every row where BAR doesn’t equal 'A'? Yes. Except the ones where BAR is NULL. And those rows will miss again.

SELECT * FROM FOO WHERE BAR <> 'A' OR BAR IS NULL;

is the way to go if we really want everything except where BAR is 'A'.

Moral of the story, I should read the documentation before jumping to conclusions, as it clearly states that “If you use any other condition with nulls and the result depends on the value of the null, then the result is UNKNOWN.” and also that “A condition that evaluates to UNKNOWN acts almost like FALSE. For example, a SELECT statement with a condition in the WHERE clause that evaluates to UNKNOWN returns no rows.”

(And of course it behaves the same with UPDATEs and not just with SELECTs.)

Too many beans

Situation: I have a Weblogic container, an application, which I would like to deploy with an ant script and an error message saying:

[wlst] Exception in thread "main" java.lang.IllegalStateException: Traceback (innermost last):
[wlst]   File "/local/bmiklos/projects/.../build/container/weblogic12/weblogic_setup_server.py", line 28, in ?
[wlst]   File "/local/bmiklos/container/weblogic/12.1.1.0.4/server/wlserver/common/wlst/weblogic_base.py", line 328, in createDataSource
[wlst] weblogic.descriptor.BeanAlreadyExistsException: Bean already exists: "weblogic.j2ee.descriptor.wl.JDBCPropertyBeanImpl@8218c7([...]/JDBCDriverParams/Properties/Properties[user])"
[wlst]     at weblogic.descriptor.internal.ReferenceManager.registerBean(ReferenceManager.java:232)
[wlst]     at weblogic.j2ee.descriptor.wl.JDBCPropertiesBeanImpl.setProperties(JDBCPropertiesBeanImpl.java:133)
[wlst]     at weblogic.j2ee.descriptor.wl.JDBCPropertiesBeanImpl.addProperty(JDBCPropertiesBeanImpl.java:79)
[wlst]     at weblogic.j2ee.descriptor.wl.JDBCPropertiesBeanImpl.createProperty(JDBCPropertiesBeanImpl.java:152)
[wlst]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[wlst]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
[wlst]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[wlst]     at java.lang.reflect.Method.invoke(Method.java:601)
[wlst]     at weblogic.management.jmx.modelmbean.WLSModelMBean.invoke(WLSModelMBean.java:437)
[wlst]     at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
[wlst]     at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:792)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase$16.run(WLSMBeanServerInterceptorBase.java:449)
[wlst]     at java.security.AccessController.doPrivileged(Native Method)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase.invoke(WLSMBeanServerInterceptorBase.java:447)
[wlst]     at weblogic.management.mbeanservers.internal.JMXContextInterceptor.invoke(JMXContextInterceptor.java:263)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase$16.run(WLSMBeanServerInterceptorBase.java:449)
[wlst]     at java.security.AccessController.doPrivileged(Native Method)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase.invoke(WLSMBeanServerInterceptorBase.java:447)
[wlst]     at weblogic.management.mbeanservers.edit.internal.RecordingInterceptor.invoke(RecordingInterceptor.java:199)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase$16.run(WLSMBeanServerInterceptorBase.java:449)
[wlst]     at java.security.AccessController.doPrivileged(Native Method)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase.invoke(WLSMBeanServerInterceptorBase.java:447)
[wlst]     at weblogic.management.mbeanservers.internal.SecurityMBeanMgmtOpsInterceptor.invoke(SecurityMBeanMgmtOpsInterceptor.java:65)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase$16.run(WLSMBeanServerInterceptorBase.java:449)
[wlst]     at java.security.AccessController.doPrivileged(Native Method)
[wlst]     at weblogic.management.jmx.mbeanserverTraceback (innermost last):
[wlst]   File "/local/bmiklos/projects/.../build/container/weblogic12/we.WLSMBeanServerInterceptorBase.invoke(WLSMBeanServerInterceptorBase.java:447)
[wlst]     at weblogic.management.mbeanservers.edit.internal.EditLockInterceptor.invoke(EditLockInterceptor.java:112)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase$blogic_setup_server.py", line 28, in ?
[wlst]   File "/local/bmiklos/container/weblogic/12.1.1.0.4/server/wlserver/common/wlst/weblogic16.run(WLSMBeanServerInterceptorBase.java:449)
[wlst]     at java.security.AccessController.doPrivileged(Native Method)
[wlst]     at weblogic.manag_base.py", line 328, in createDataSource
[wlst] weblogic.descriptor.BeanAlreadyExistsException: Bean already exists: "weblogic.j2ee.desement.jmx.mbeanserver.WLSMBeanServerInterceptorBase.invoke(WLSMBeanServerInterceptorBase.java:447)
[wlst]     at weblogic.management.mbeancriptor.wl.JDBCPropertyBeanImpl@8218c7([MB-DS]/JDBCDriverParams/Properties/Properties[user])"
[wlst]     at weblogic.descriptor.inteservers.internal.SecurityInterceptor.invoke(SecurityInterceptor.java:444)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerrnal.ReferenceManager.registerBean(ReferenceManager.java:232)
[wlst]     at weblogic.j2ee.descriptor.wl.JDBCPropertiesBeanImpl.setProperti.invoke(WLSMBeanServer.java:323)
[wlst]     at weblogic.management.mbeanservers.internal.JMXConnectorSubjectForwarder$11$1.run(JMXConnectoes(JDBCPropertiesBeanImpl.java:133)
[wlst]     at weblogic.j2ee.descriptor.wl.JDBCPropertiesBeanImpl.addProperty(JDBCPropertiesBeanImpl.jarSubjectForwarder.java:663)
[wlst]     at java.security.AccessController.doPrivileged(Native Method)
[wlst]     at weblogic.management.mbeanservers.va:79)
[wlst]     at weblogic.j2ee.descriptor.wl.JDBCPropertiesBeanImpl.createProperty(JDBCPropertiesBeanImpl.java:152)
[wlst]     at sun.reflect.Nainternal.JMXConnectorSubjectForwarder$11.run(JMXConnectorSubjectForwarder.java:661)
[wlst]     at weblogic.security.acl.internal.AuthentictiveMethodAccessorImpl.invoke0(Native Method)
[wlst]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
[wlst] atedSubject.doAs(AuthenticatedSubject.java:363)
[wlst]     at weblogic.management.mbeanservers.internal.JMXConnectorSubjectForwarder.invok    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[wlst]     at java.lang.reflect.Method.invoke(Mee(JMXConnectorSubjectForwarder.java:654)
[wlst]     at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:14thod.java:601)
[wlst]     at weblogic.management.jmx.modelmbean.WLSModelMBean.invoke(WLSModelMBean.java:437)
[wlst]     at com.sun.jmx.interceptor.D86)
[wlst]     at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:96)
[wlst]     at javax.management.remote.rmi.RMICefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
[wlst]     at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmonnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1327)
[wlst]     at java.security.AccessController.doPrivileged(Native MethodxMBeanServer.java:792)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase$16.run(WLSMBeanServerInterceptorBas)
[wlst]     at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1426)
[wlst]     at javax.management.remoe.java:449)
[wlst]     at java.security.AccessController.doPrivileged(Native Method)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServete.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:847)
[wlst]     at javax.management.remote.rmi.RMIConnectionImpl_WLSkel.invoke(UnknrInterceptorBase.invoke(WLSMBeanServerInterceptorBase.java:447)
[wlst]     at weblogic.management.mbeanservers.internal.JMXContextIntercepown Source)
[wlst]     at weblogic.rmi.internal.BasicServerRef.invoke(BasicServerRef.java:693)
[wlst]     at weblogic.rmi.internal.BasicServerRef$1.tor.invoke(JMXContextInterceptor.java:263)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase$16.run(WLSMBeanrun(BasicServerRef.java:518)
[wlst]     at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:363)
[wlst]     at webServerInterceptorBase.java:449)
[wlst]     at java.security.AccessController.doPrivileged(Native Method)
[wlst]     at weblogic.management.jmx.mbeanlogic.security.service.SecurityManager.runAs(SecurityManager.java:146)
[wlst]     at weblogic.rmi.internal.BasicServerRef.handleRequest(Baserver.WLSMBeanServerInterceptorBase.invoke(WLSMBeanServerInterceptorBase.java:447)
[wlst]     at weblogic.management.mbeanservers.edit.insicServerRef.java:514)
[wlst]     at weblogic.rmi.internal.wls.WLSExecuteRequest.run(WLSExecuteRequest.java:118)
[wlst]     at weblogic.work.Executeternal.RecordingInterceptor.invoke(RecordingInterceptor.java:199)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerIntercepThread.execute(ExecuteThread.java:256)
[wlst]     at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
[wlst]
[wlst] weblogic.descriptor.BeanAlretorBase$16.run(WLSMBeanServerInterceptorBase.java:449)
[wlst]     at java.security.AccessController.doPrivileged(Native Method)
[wlst]     at weblogadyExistsException: weblogic.descriptor.BeanAlreadyExistsException: Bean already exists: "weblogic.j2ee.descriptor.wl.JDBCProperic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase.invoke(WLSMBeanServerInterceptorBase.java:447)
[wlst]     at weblogic.managemetyBeanImpl@8218c7([MB-DS]/JDBCDriverParams/Properties/Properties[user])"
[wlst]
[wlst]     at weblogic.management.scripting.WLSTInterpretent.mbeanservers.internal.SecurityMBeanMgmtOpsInterceptor.invoke(SecurityMBeanMgmtOpsInterceptor.java:65)
[wlst]     at weblogic.managementrInvoker.printError(WLSTInterpreterInvoker.java:146)
[wlst]     at weblogic.management.scripting.WLSTInterpreterInvoker.executePyScript(WL.jmx.mbeanserver.WLSMBeanServerInterceptorBase$16.run(WLSMBeanServerInterceptorBase.java:449)
[wlst]     at java.security.AccessControllerSTInterpreterInvoker.java:111)
[wlst]     at weblogic.management.scripting.WLSTInterpreterInvoker.main(WLSTInterpreterInvoker.java:30)
[wlst] .doPrivileged(Native Method)
[wlst]     at weblogic.management.jmx.mbeanserver.WLSMBeanServerInterceptorBase.invoke(WLSMBeanServerInterceptorBase.java:447)
[wlst]     at weblogic.management.mbeanservers.edit

The problem in my case is that the container gets corrupt somehow, so I need to delete the directory containing it and re-create the whole thing. After that deploying my application works again.

Velocity template not showing results from Java method call

We can call methods of any Java class from Apache Velocity. Now if that method happens to return a List<String>, and then process that list with #foreach, then we should be aware that in Velocity the result will be something like [foo, bar] instead of ["foo", "bar"]. We will get an array of texts and not an array of strings. If we assume that we get strings and try to manipulate them that way, let’s say by calling toUpperCase() on them Velocity may just decide to ignore that method call on a thing that doesn’t have that method and show nothing as a result. No error messages either. Making it quite hard to figure out what went wrong. At least this happened in my case.

Struts validation variable back referencing

Old Struts 1.x project.  I’m new to Struts and I was trying to validate a string with minlength, and if the length is not enough, then display an error message which contains the original string and the length of the original string. Not because it makes sense, but because that’s what I am asked to do. And I’m trying to do this with the validation XML, because all of the project’s validation stuff is declared in XML files.
Struts has a relatively good documentation, with examples and everything, but they don’t really mention anywhere how their extra stuff, like *this* works. Anyway, *this* was the closest thing that I could find to solve my problem, so I gave it a try. After a few tries my validation XML looked like this:

<field property="input" depends="minlength">
    <arg0 key="search.string" />
    <arg1 name="minlength" key="${var:minlength}" resource="false" />
    <arg2 name="minlength" key="${var:input}" resource="false" />
    <arg3 name="minlength" key="${var:length}" resource="false" />
    <var>
        <var-name>minlength</var-name>
        <var-value>15</var-value>
    </var>
    <var>
        <var-name>input</var-name>
        <var-value>*this*</var-value>
    </var>
    <var>
        <var-name>length</var-name>
        <var-value>(*this*).length()</var-value>
    </var>
</field>

but it doesn’t work, it just put “*this*” and “(*this*).length()” into the error message. (Which is kind of understandable.)
Then I put the question on Stackoverflow, then nobody answered for a long time. And after consulting with a senior developer I came to the conclusion that this most likely can’t be done with a validation XML file. I put this here so if others try to still do something like this in legacy code like this. But there are other ways to validate in Struts too and they are more flexible than the XML.
Just in case anybody has to do anything like this on a legacy project… there you go.

Setting up PHP CodeSniffer with NetBeans

I’m setting up phpMD / CodeSniffer into my NetBeans 7.3 on Xubuntu 12.10 again, so that I don’t have to look all the stuff up again.

First I install the plugin.

Then it complains that the underlying stuff isn’t properly configured. (Of course it isn’t as I haven’t installed anything else yet.)

Let’s start with Mess Detector, as its webpage suggests.

sudo pear channel-discover pear.phpmd.org
sudo pear remote-list -c phpmd
sudo pear install phpmd/PHP_PMD

Now NetBeans’s options dialog can detect Mess Detector and it says it works fine.
The next one will be CodeSniffer.

sudo pear install PHP_CodeSniffer

And after NetBeans detects it, I set the ‘standard’ field to ‘Zend’ instead of ‘PEAR’.

The only one that remains is Copy Paste Detector. Installing it as its webpage suggests. Note: php-unit should not be installed through apt or it would cause some problems.

sudo pear config-set auto_discover 1
sudo pear install pear.phpunit.de/phpcpd

Debugging ‘No writers were added’ error

Recently I got some

PHP Fatal error: Uncaught exception 'Zend_Log_Exception' with message 'No writers were added'

messages in the Apache error log file. The reason is most of the time (at least in my projects) is that the Zend_Log_Writer_Stream constructor returns null. Just a reminder to myself how to solve the problem:

  1. make sure the path to the file exists
  2. if that didn’t help, make sure the file exists
  3. if that didn’t help, make sure the file is writeable by www-data.
    sudo chown www-data file.log and sudo chmod u+w file.log should do the trick.
  4. if that didn’t help, make sure the file is writeable by others.
    sudo chmod o+w file.log should do the trick.
    (No. This one should not be done. It’s bad practice, insecure, and everything. It can be used only to test that after so many hours of debugging I’m still sane, and file permissions aren’t the issue here. Or to figure out that in this particular case it isn’t www-data who wants to write the file, but some other user, for example because it’s a command line PHP script running as another user.)
  5. if that didn’t help, make sure the file isn’t open anywhere else. In my case the problem was that there was a Zend_Log descendant singleton which held a static copy of the Zend_Log_Writer_Stream which never got closed. (As an irrelevant note, we should do code reviews more often.)