Friday, December 11, 2009
maven assembly plugin
What do you do?
you call the maven assembly plugin to the rescue and define several executions
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>MatchLibrary</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>edu.ucdavis.genomics.metabolomics.binbase.binbase.external.tools.api.library.impl.application.ApplicationServerLibraryMatchingImplementation</mainClass>
<packageName>edu.ucdavis.genomics.metabolomics.binbase.binbase.external.tools.api.library.impl.application</packageName>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<mode>development</mode>
<url>${pom.url}</url>
</manifestEntries>
<manifestFile>src/main/resources/manifest/ApplicationServerLibraryMatchingImplementation.MF</manifestFile>
</archive>
<descriptors>
<descriptor>src/main/descriptor/jar.xml</descriptor>
</descriptors>
<finalName>MatchLibrary</finalName>
<manifestFile>src/main/resources/manifest/ApplicationServerLibraryMatchingImplementation.MF</manifestFile>
</configuration>
</execution>
<execution>
<id>RegisterLibrary</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>edu.ucdavis.genomics.metabolomics.binbase.binbase.external.tools.api.library.impl.RegisterLibraryImpl</mainClass>
<packageName>edu.ucdavis.genomics.metabolomics.binbase.binbase.external.tools.api.library.impl</packageName>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<mode>development</mode>
<url>${pom.url}</url>
</manifestEntries>
<manifestFile>src/main/resources/manifest/RegisterLibrary.MF</manifestFile>
</archive>
<descriptors>
<descriptor>src/main/descriptor/jar.xml</descriptor>
</descriptors>
<finalName>RegisterLibrary</finalName>
<manifestFile>src/main/resources/manifest/RegisterLibrary.MF</manifestFile>
</configuration>
</execution>
</executions>
</plugin>
and this generates two executable jars for us.
The used assembly descriptor is
<assembly>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target/classes</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
Tuesday, December 8, 2009
jboss maven plugin
All it basically does is to parse the local jboss installation and depoys the files in the local repository.
Simple and efficient.
It can be found here
Wednesday, November 18, 2009
SQL - small mistakes, big impact
After working for hours on different parameters and tuning the database, including setting up a spare server to see if a dump and restore fixes the issues I got the time down to 5 minutes.
Sounds good?
well not really since I needed an execution in the range of a couple of seconds. So I actually looked at the sql statement which caused issues and found a gigantic error in it...
the statement:
select * from BIN where bin_id not in ( SELECT bin_id from SPECTRA where sample_id = 424105 AND SPECTRA.bin_id = BIN.bin_id)
and the correct statement would be:
select * from BIN a where a.bin_id not in ( SELECT bin_id from SPECTRA where sample_id = 424105 and bin_id is not null) ORDER BY retention_index ASC
the problem?
SPECTRA.bin_id = BIN.bin_id
this little part is totally wrong in the whole statement and causes a seq scan over a table with 70 Million entries against a table with 6000 entries. It does nothing for the queries and I guess it was left over from a copy/paste accident 6 years ago when I wrote this script originally.
let's compare some numbers:
explain before:
Seq Scan on bin (cost=0.00..459513.42 rows=3044 width=1290)
SubPlan
Filter: (NOT (subplan))
-> Bitmap Heap Scan on spectra (cost=75.20..75.42 rows=2 width=8)
Recheck Cond: ((sample_id = 424105::double precision) AND (bin_id = ($0)::double precision))
-> BitmapAnd (cost=75.20..75.20 rows=2 width=0)
-> Bitmap Index Scan on spectra_sample_id (cost=0.00..18.99 rows=5696 width=0)
-> Bitmap Index Scan on spectra_binid (cost=0.00..56.18 rows=17658 width=0)
Index Cond: (sample_id = 424105::double precision)
Index Cond: (bin_id = ($0)::double precision)
explain after:
Sort (cost=1765.47..1766.23 rows=3044 width=1290)
Sort Key: retention_index
-> Seq Scan on bin a (cost=647.21..1747.86 rows=3044 width=1290)
Filter: (NOT (hashed subplan))
SubPlan
-> Index Scan using spectra_sample_id on spectra (cost=0.00..646.42 rows=3138 width=8)
Index Cond: (sample_id = 424105::double precision)
Filter: (bin_id IS NOT NULL)
in real world number this translates to 24 hours before statement compared to 4 seconds after statement...
...
Tuesday, November 17, 2009
maven2 - choose dependcies based on platform
So promptly it fails to compile under linux...
solution for this problem?
maven2 profiles, your best friend for cross platform development. They actually allow you define dependencies based on the current platform.
Example for out case would be:
<profiles>
<profile>
<id>dev-windows</id>
<dependencies>
</dependencies>
<activation>
<activeByDefault>true</activeByDefault>
<os>
<family>windows</family>
</os>
</activation>
</profile>
<profile>
<id>dev-mac</id>
<dependencies>
<dependency>
<groupId>psteclipse</groupId>
<artifactId>org.eclipse.swt.cocoa.macosx</artifactId>
<version>3.5.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<activation>
<activeByDefault>false</activeByDefault>
<os>
<family>mac</family>
</os>
</activation>
</profile>
<profile>
<id>dev-linux</id>
<dependencies>
<dependency>
<groupId>psteclipse</groupId>
<artifactId>org.eclipse.swt.gtk.linux.x86</artifactId>
<version>3.5.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<activation>
<activeByDefault>false</activeByDefault>
<os>
<name>linux</name>
</os>
</activation>
</profile>
</profiles>
And sets a different library for osx and linux. Sweet!
Wednesday, November 11, 2009
hibernate - configure caching
Well
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>
so this makes the binbase configuration run in the eclipse tools.
Monday, November 2, 2009
Log4J and eclipse
The use of this is rather simple and straight forwarded. You only need to register an ILogListener at the platform object and implement it.
An example would be:
package edu.ucdavis.genomics.metabolomics.binbase.gui.swt.logging;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.ILogListener;
import org.eclipse.core.runtime.IStatus;
/**
* used to forward eclipse logging to log4j
*
* @author wohlgemuth
*
*/
public class Log4JListener implements ILogListener {
static Logger LOGGER = Logger.getLogger(Log4JListener.class);
public void logging(IStatus status, String plugin) {
if (status.getSeverity() == IStatus.WARNING) {
if (status.getException() == null) {
LOGGER.warn(status.getMessage() + "(" + status.getCode() + ")");
} else {
LOGGER.warn(status.getMessage() + "(" + status.getCode() + ")",
status.getException());
}
} else if (status.getSeverity() == IStatus.ERROR) {
if (status.getException() == null) {
LOGGER
.error(status.getMessage() + "(" + status.getCode()
+ ")");
} else {
LOGGER.error(
status.getMessage() + "(" + status.getCode() + ")",
status.getException());
}
} else if (status.getSeverity() == IStatus.INFO) {
if (status.getException() == null) {
LOGGER.info(status.getMessage() + "(" + status.getCode() + ")");
} else {
LOGGER.info(status.getMessage() + "(" + status.getCode() + ")",
status.getException());
}
}
}
}
and to register it
this.listener = new Log4JListener();
Platform.addLogListener(this.listener);
Tuesday, October 27, 2009
Eclipse SWT 3.5 and an annoying change...
For example the login dialog has 2 fiels. A username and a password. These fields are defiend like this:
password = new Text(content, SWT.BORDER | SWT.PASSWORD);
user = new Text(content, SWT.BORDER);
user.addKeyListener(this);
password.addKeyListener(this);
and in the key listener I validate the inputs. But with version 3.5 key listener won't work on password fields anymore and I didn't find any documentation about it. So instead you need to use a modify listener now
password.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
}
});
Friday, October 23, 2009
duplicating a disk under OSX
How to do this?
1. Insert CD/DVD source
2. Fire up a Terminal, you can then determine the device that is you CD/DVD drive using the following command:
$ drutil status Vendor Product Rev MATSHITA DVD-R UJ-835E GAND Type: DVD-ROM Name: /dev/disk1 Cur Write: 8x DVD Sessions: 1 Max Write: 8x DVD Tracks: 1 Overwritable: 00:00:00 blocks: 0 / 0.00MB / 0.00MiB Space Free: 00:00:00 blocks: 0 / 0.00MB / 0.00MiB Space Used: 364:08:27 blocks: 1638627 / 3.36GB / 3.13GiB Writability: Book Type: DVD-ROM3. Umount the disk with the following command:
$ diskutil unmountDisk /dev/disk1 Disk /dev/disk1 unmounted4. Create the ISO file with the dd utility (may take some time):
$ dd if=/dev/disk1 of=file.iso bs=20485. Test the ISO image by mounting the new file (or open with Finder):
$ hdid file.iso
taken from here
Friday, October 16, 2009
OSX - upgraded my macbook pro to an SSD and the differences
Now the tests are clear:
SSD
Drive Type CORSAIR CMFSSD-128GBG2D
Disk Test 173.68
Sequential 132.15
Uncached Write 143.67 88.21 MB/sec [4K blocks]
Uncached Write 101.53 57.44 MB/sec [256K blocks]
Uncached Read 94.19 27.56 MB/sec [4K blocks]
Uncached Read 351.79 176.81 MB/sec [256K blocks]
Random 253.29
Uncached Write 121.43 12.85 MB/sec [4K blocks]
Uncached Write 196.26 62.83 MB/sec [256K blocks]
Uncached Read 1503.47 10.65 MB/sec [4K blocks]
Uncached Read 556.60 103.28 MB/sec [256K blocks]
Drive Type ST9500325AS
Disk Test 43.26
Sequential 80.53
Uncached Write 78.89 48.44 MB/sec [4K blocks]
Uncached Write 68.76 38.91 MB/sec [256K blocks]
Uncached Read 77.68 22.73 MB/sec [4K blocks]
Uncached Read 104.42 52.48 MB/sec [256K blocks]
Random 29.57
Uncached Write 10.43 1.10 MB/sec [4K blocks]
Uncached Write 73.40 23.50 MB/sec [256K blocks]
Uncached Read 64.02 0.45 MB/sec [4K blocks]
Uncached Read 98.74 18.32 MB/sec [256K blocks]
I think these result's speak for them self!
my trouble with snowleopard and java5
Luckily there is an easy fix to it!
taken from here
cd /tmp/
curl -o java.1.5.0-leopard.tar.gz http://www.cs.washington.edu/homes/isdal/snow_leopard_workaround/java.1.5.0-leopard.tar.gz
tar -xvzf java.1.5.0-leopard.tar.gz
sudo mv 1.5.0 /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0-leopard
cd /System/Library/Frameworks/JavaVM.framework/Versions/
sudo rm 1.5.0
sudo ln -s 1.5.0-leopard 1.5.0
open "/Applications/Utilities/Java Preferences.app"
and move java5 to the top.
Wednesday, October 7, 2009
calculating the variance - groovy style
static double variance(def population) {
long n = 0
double mean = 0
double s = 0.0
population.each {double x ->
n++;
double delta = x - mean
mean += delta / n
s += delta * (x - mean)
}
(s / (n - 1))
}
Thursday, September 17, 2009
Strange XMLParser behaviour - Groovy 1.6.4
So this is my code:
new StreamingMarkupBuilder().bind({
sop(desc: "generated for quantification") {
transform(sizedown: 0, attributes: "height", combine: true) {
header{
param(value:"retention_index")
param(value:"quantmass")
param(value:"id")
param(value:"spectra")
}
}
}
simple enough.
And that's the code to test it
def parser = new XmlParser().parse(source.getStream())
assertTrue parser.@desc != null
assertTrue parser.transform != null
assertTrue Integer.parseInt(parser.transform.@sizedown[0]) == 0
assertTrue parser.transform.@attributes[0] == "height"
assertTrue parser.transform.@combine[0] == "true"
assertTrue parser.transform.header.param[0].@value == "retention_index"
assertTrue parser.transform.header.param[1].@value == "quantmass"
assertTrue parser.transform.header.param[2].@value == "id"
assertTrue parser.transform.header.param[3].@value == "spectra"
assertTrue parser.transform.header.param.size() == 4
also pretty straight forward.
Now why is this part different...
transform(sizedown: 0, attributes: "height", combine: true)
assertTrue Integer.parseInt(parser.transform.@sizedown[0]) == 0
assertTrue parser.transform.@attributes[0] == "height"
assertTrue parser.transform.@combine[0] == "true"
and my attributes are returned as an array list compared to
header{
param(value:"retention_index")
param(value:"quantmass")
param(value:"id")
param(value:"spectra")
}
assertTrue parser.transform.header.param[0].@value == "retention_index"
assertTrue parser.transform.header.param[1].@value == "quantmass"
assertTrue parser.transform.header.param[2].@value == "id"
assertTrue parser.transform.header.param[3].@value == "spectra"
where the attributes are returned as simple string. I has to be something obvious, but right now I'm not getting it.
Wednesday, September 16, 2009
XMLMarkupBuilder in groovy.
So I gave it a shot
def document = new StreamingMarkupBuilder().bind({
config {
parameter {
param(name: "java.naming.provider.url", value: "127.0.0.1", public:true)
param(name: "java.naming.factory.initial", value: "org.jnp.interfaces.NamingContextFactory", public:true)
param(name: "java.naming.factory.url.pkgs", value: "org.jboss.naming:org.jnp.interfaces", public:true)
param(name: "edu.ucdavis.genomics.metabolomics.util.status.ReportFactory", value: "edu.ucdavis.genomics.metabolomics.binbase.cluster.status.EJBReportFactory")
param(name: "edu.ucdavis.genomics.metabolomics.util.thread.locking.LockableFactory", value: "edu.ucdavis.genomics.metabolomics.binbase.cluster.locking.EJBLockingFactory")
}
}
})
println document
and the result is
<config><parameter><param name='java.naming.provider.url' value='127.0.0.1' public='true'/><param name='java.naming.factory.initial' value='org.jnp.interfaces.NamingContextFactory'/><param name='java.naming.factory.url.pkgs' value='org.jboss.naming:org.jnp.interfaces'/><param name='edu.ucdavis.genomics.metabolomics.util.status.ReportFactory' value='edu.ucdavis.genomics.metabolomics.binbase.cluster.status.EJBReportFactory'/><param name='edu.ucdavis.genomics.metabolomics.util.thread.locking.LockableFactory' value='edu.ucdavis.genomics.metabolomics.binbase.cluster.locking.EJBLockingFactory'/></parameter></config>
Neat! This was very simple and the validation of the code happens at runtime. The only uggly part is that idea shows this part in red brackets
public:true
since public is a keyword of java/groovy. But it does compile...
Guess I have to change my api a bit to avoid this uggly keyword or at least make it optional.
Tuesday, September 15, 2009
Groovy 1.6.4 + IntelliJ8 + Groovy Plugin - nullpointer
They only happen if I execute the project from intelliJ out.
example for this would be:
src/example/dsl/quant.dsl
Caught: java.lang.NullPointerException
java.lang.NullPointerException
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:39)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at edu.ucdavis.genomics.metabolomics.binbase.quantificator.dsl.QuantificatorDSL.run(QuantificatorDSL.groovy:45)
at edu.ucdavis.genomics.metabolomics.binbase.quantificator.dsl.QuantificatorDSL$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at edu.ucdavis.genomics.metabolomics.binbase.quantificator.dsl.QuantificatorDSL.main(QuantificatorDSL.groovy:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:592)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234)
at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1296)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:719)
at groovy.lang.GroovyShell.runScriptOrMainOrTestOrRunnable(GroovyShell.java:262)
at groovy.lang.GroovyShell.run(GroovyShell.java:218)
at groovy.lang.GroovyShell.run(GroovyShell.java:147)
at groovy.ui.GroovyMain.processOnce(GroovyMain.java:493)
at groovy.ui.GroovyMain.run(GroovyMain.java:308)
at groovy.ui.GroovyMain.process(GroovyMain.java:294)
at groovy.ui.GroovyMain.processArgs(GroovyMain.java:111)
at groovy.ui.GroovyMain.main(GroovyMain.java:92)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:592)
at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:108)
at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130)
Now this exception does not occur, if I make a complete rebuild.
For some reason it is not able to initialize a class if it defined in another source file. More about this is written here
Thursday, September 10, 2009
groovy 1.5.6 and delegates
example:
class MyDelegate {
def test() {
println "tada"
}
}
static ExpandoMetaClass createEMC(Class clazz, Closure cl) {
ExpandoMetaClass emc = new ExpandoMetaClass(clazz, false)
cl(emc)
emc.initialize()
return emc
}
Script dslScript = new GroovyShell().parse("test{\ntest()\n}")
dslScript.metaClass = createEMC(dslScript.class, {
ExpandoMetaClass emc ->
emc.test = {
Closure closure ->
closure.delegate = new MyDelegate()
closure.resolveStrategy = Closure.DELEGATE_FIRST
try {
closure()
}
catch (Exception e) {
e.printStackTrace()
}
}
})
dslScript.run()
this works fine. Now if I move the class 'MyDelegate' to it's own file I end up with the following exception.
java.lang.NullPointerException
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.getDelegateMethod(ClosureMetaClass.java:207)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:280)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnCurrentN(ScriptBytecodeAdapter.java:78)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnCurrent0(ScriptBytecodeAdapter.java:112)
at Script1$_run_closure1.doCall(Script1.groovy:2)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:248)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnCurrentN(ScriptBytecodeAdapter.java:78)
at Script1$_run_closure1.doCall(Script1.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:248)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756)
at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:778)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:758)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeClosure(ScriptBytecodeAdapter.java:605)
at edu.ucdavis.genomics.metabolomics.binbase.quantificator.dsl.Tester$_run_closure1_closure2.doCall(Tester.groovy:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:248)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756)
at groovy.lang.Closure.call(Closure.java:292)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke(ClosureMetaMethod.java:72)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:912)
at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:946)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnCurrentN(ScriptBytecodeAdapter.java:78)
at Script1.run(Script1.groovy:1)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:912)
at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:946)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756)
at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:778)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:758)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethod0(ScriptBytecodeAdapter.java:198)
at edu.ucdavis.genomics.metabolomics.binbase.quantificator.dsl.Tester.run(Tester.groovy:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:912)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756)
at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:778)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:758)
at org.codehaus.groovy.runtime.InvokerHelper.runScript(InvokerHelper.java:401)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1105)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:749)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170)
at edu.ucdavis.genomics.metabolomics.binbase.quantificator.dsl.Tester.main(Tester.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1105)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:749)
at groovy.lang.GroovyShell.runMainOrTestOrRunnable(GroovyShell.java:244)
at groovy.lang.GroovyShell.run(GroovyShell.java:218)
at groovy.lang.GroovyShell.run(GroovyShell.java:147)
at groovy.ui.GroovyMain.processOnce(GroovyMain.java:493)
at groovy.ui.GroovyMain.run(GroovyMain.java:308)
at groovy.ui.GroovyMain.process(GroovyMain.java:294)
at groovy.ui.GroovyMain.processArgs(GroovyMain.java:111)
at groovy.ui.GroovyMain.main(GroovyMain.java:92)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:101)
at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130)
time to give groovy 1.6.4 a try and maybe migrate my project over to it.
Wednesday, September 9, 2009
DSL - love or hate?
The approach of XML is great, but I'm not a big fan of the overhead with it.
So the first approach was to create a DSL for the BinBase system, precisely to provide the user with a really simple way of calculating an experiment.
It should look something like this:
/**
* our quantification dsl
*/
quantify {
//define the name of the setup
name "quantification for ${new Date()}"
//define the samples for the calculations
sample "sample 1"
sample "sample 2"
sample "sample 3"
sample "sample 4"
sample "sample 5"
sample "sample 6"
sample "sample 7"
sample "sample 8"
sample "sample 9"
sample "sample 10"
//defines the bins in the table
bin 321, 22.0
bin 322
bin 323
bin 324
bin 325, 22.0
//report definition
report {
sizeDown 50
format "xls"
replace true
}
}
And the result should calculate the data, send them to the cluster and generates a quantification report. If this all works out the way we want it. We will than adapt it to schedule BinBase experiment's this way.
My current fazit is that I love the idea of DSL's, but hate the implementations of it.
jboss - binding to all registered network cards
Since this is not desired in a production system you can override this feature with the '-b' command.
An example to start jboss in the all configuration and bound to all registered interfaces would be
sh run.sh -b 0.0.0.0 -c all
Thursday, September 3, 2009
creating a project with maven2
mvn archetype:create -DgroupId=myGroup -DartifactId=myArtifact
so I write it down here to make it easier for me to lookup.
Wednesday, September 2, 2009
osx - set disk as startup disk via terminal
sudo bless -mount /Volumes/"name of your startup disk" -setBoot
Tuesday, September 1, 2009
run-app vs run-war
run-app runs a grails applications and allows the reloading from resources
run-war generates a war file and runs the war file, so no reloading of resources.
Short during development you want to use run-app.
Monday, August 31, 2009
maven2 - define the context root of an webapp
Solution:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
<jboss>
<version>4</version>
</jboss>
<bundleFileName>
binbase-quality-control.ear
</bundleFileName>
<modules>
<webModule>
<groupId>edu.ucdavis.genomics.metabolomics.binbase.quality
</groupId>
<artifactId>quality-war</artifactId>
<contextRoot>/quality-war</contextRoot>
</webModule>
</modules>
</configuration>
</plugin>
Sunday, August 9, 2009
Method "ApplyConfiguration" with signature "" on interface "org.gnome.SettingsDaemon.XRANDR" doesn't exist
Sadly since ubuntu 8.something I kept getting the following error message
Method "ApplyConfiguration" with signature "" on interface "org.gnome.SettingsDaemon.XRANDR" doesn't exist
So I upgraded to the newest ubuntu version. Didn't make it much better. So I could had given up here and start shouting all kinds off stuff about linux or trying to make it work.
So here is the solution:
the gui is basically broken and you need to execute the commands to adjust everything your self. Using 'xandr'
for example to turn off a monitor:
xandr --output LVDS --off
or to change the resolution
xandr --output DVI-0 --mode 1360x768 --pos 0x0
2 minutes later I had my configuration up and running.
Tuesday, August 4, 2009
synchornized groovy
I want to have a websites which fires calculations to a database server, but the controller should only execute one calculation at a time
how do you do this?
The first approach was to try to queue the ajax calls, which obviously won't work if two people run calculations at the same time.
So plan b was to use synchronized groovy code.
/**
* does the actual calculation
*/
def calculate_ajax = {
assert params.database != null, "you need to provide 'database' in the params object"
assert params.date != null, "you need to provide 'date' in the params object"
assert params.machine != null, "you need to provide 'machine' in the params object"
assert params.pattern != null, "you need to provide 'pattern' in the params object"
assert params.position != null, "you need to provide 'position' in the params object"
//needs to be synchronized so we don't kill the database server with this task
synchronized (LOCK) {
println new Date()
BinBaseQualityConnector.getQualityService().calculateSingleStandard(params.pattern, params.database, new Date(Long.parseLong(params.date)), params.machine, BinBaseQualityConnector.getKey())
render("<div class=\"after_complete\" style=\"width:${100 / BinBaseQualityConnector.getPattern(params).size()}%\"></div>")
}
}
static final def LOCK = "lock"
and a possible ajax call for this looks like this
<script type="text/javascript">
YAHOO.util.Event.onDOMReady(
function() {
new Ajax.Updater('${i}_${y}_${z}', '/quality-war/processing/calculate_ajax', {
method: 'get', frequency: 3,parameters:'date=${date.getTime()}&database=${database}&machine=${machine}&pattern=${pattern}&position=${z}'
});
});
</script>
Tuesday, July 28, 2009
updating more than one div with grails and ajax
Now you can either reload the complete page, which can take a while with a lot of data or just queue remote functions in a java script function like this
function addStandard() {
if (YAHOO.example.container.addstandard) {
YAHOO.example.container.addstandard.hide();
}
//get our element values
var conc = document.getElementsByName('qs_concentration')[0].value;
var pattern = document.getElementsByName('qs_pattern')[0].value;
//calls the remote functions
${remoteFunction(
controller: 'management',
action: 'addStandard_ajax',
params: '\'conc=\' + escape(conc) + \'&pattern=\' + escape(pattern)',
update: 'registered_standards')}
${remoteFunction(
controller: 'messenger',
action: 'showMessage',
params: '\'message=you should recalculate the database now!\'',
update: 'messenger')}
}
javascripts and maps
var test = new Object();
test['tada'] = 'yada';
alert(test['yada']);
alert(test.yada);
distinct or group by, what's more expensive
Distinct or group by '*'
select name from table group by name
or
select distinct name from table
after all they both return the exact same result.
Some explain statements later it turned out that the group by clause is 18% faster than the distinct statement.
Monday, July 27, 2009
sometimes it's simpler to use plain ajax...
Solution:
<div class="center">
<img name="${bin.getId()}" src="${createLinkTo(dir: 'images', file: 'remove.gif')}" alt="zoom" onclick="new Ajax.Updater
('bin-container-${db}', '/quality-war/management/remove_bin_ajax', {asynchronous:true,evalScripts:true,parameters
:'bin=${bin.getId()}&database=${db}'});"/>
</div>
this also shows how to submit several parameters at once in plain ajax style.
lesson of the day...
cause if you do,
you shall be send to the hell of css,
constant torture and misfortune will await you,
so do not duplicate your id's!
problem:
updating a you tab with some dynamic generated content, which generate the same div id over and over again...
Annoying maven bug
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Error installing artifact's metadata: Error installing metadata: Error updating group repository metadata
input contained no data
[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
without actually doing any changes at the pom.xml. The problem turned out that the repository was corrupt.
So all I had todo was to delete my project from the local build repository.
Thursday, July 23, 2009
Grails - using several arguments with a remote function
After a bit of asking Dr Google I finally found an approach which worked
var conc = document.getElementsByName('qs_concentration')[0].value;
var pattern = document.getElementsByName('qs_pattern')[0].value;
${remoteFunction(
controller: 'management',
action: 'addStandard_ajax',
params: '\'conc=\' + escape(conc) + \'&pattern=\' + escape(pattern)',
update: 'registered_standards')}
now I just wish there would be an easier approach
grails remote function on image or checkbox
It's simple enough,
<img name="${standard.getPosition()}" src="${createLinkTo(dir: 'images', file: 'remove.gif')}" alt="zoom" onclick="${remoteFunction(
controller: 'management',
action: 'removeStandard_ajax',
params: '\'standard=\' + + escape(this.name)',
update: 'registered_standards')}"/>
To make live easy we just save the id in the name field of the image, but you can also save it somewhere else, depending on your requirements.
Now another thing you can do is todo the same thing for checkfields.
<input type="checkbox" id="cacheSetting" name="cacheSetting" onchange="${remoteFunction(
controller: 'management',
action: 'updateCache_ajax',
params: '\'cacheSetting=\' + escape(this.checked)',
update: 'general_config')}"/>
If you want to preserve the check state you can do this with this
<input type="checkbox" id="cacheSetting" name="cacheSetting" <%if(cacheSetting) println "checked"%> onchange="${remoteFunction(
controller: 'management',
action: 'updateCache_ajax',
params: '\'cacheSetting=\' + escape(this.checked)',
update: 'general_config')}"/>
and an example controller function could look like this
def updateCache_ajax = {
assert params.cacheSetting != null, "you need to provide \"cacheSetting\" in the params object"
BinBaseQualityConnector.getQualityConfigService().setCaching(Boolean.parseBoolean(params.cacheSetting))
//define our model
def model = new HashMap()
//build the model
model.cacheSetting = BinBaseQualityConnector.getQualityConfigService().isCaching()
render(template: "general", model: model)
}
Monday, July 20, 2009
scala in grails
I don't know why I would want to use scala right now in this, but I'm sure I find out a reason or two :)
Thursday, July 16, 2009
YUI and Prototype - updating an element
- show the content of the tab, happens by default
- update a div on the page somewhere with some content related to the tab content
Quite simple.
<script type="text/javascript">
var myTabs = new YAHOO.widget.TabView('demo');
var tab0 = myTabs.getTab(0);
function handleClick(e,tab) {
${"div_to_update"}.update("I just clicked on my tab!");
}
tab0.addListener('click', handleClick,tab0);
</script>
and as you can see we use the 'update' function from the prototype library.
Wednesday, July 15, 2009
Grails - ajax driven select and saving the selection
And some nice person wrote a great tutorial about this here, but there was one thing missing. I wanted to render some elements on the same page and keep the selection stored in the text field.
The default approach is the following grails tag:
<g:select id="machine" name="machine" value = "${machine}"/>
but since this field is populated by an ajax function, the value can never be set,since the population happens after the page is loaed, so what can we do?
We enhance our little bit of java script and define the selection in there
//update the machine tag with the received values
function updateMachine(e) {
// The response comes back as a bunch-o-JSON
var machines = eval("(" + e.responseText + ")"); // evaluate JSON
if (machines) {
var rselect = document.getElementById('machine');
// Clear all previous options
var l = rselect.length;
while (l > 0) {
l--;
rselect.remove(l) ;
}
// Rebuild the select
for (var i = 0; i < machine =" machines[i];" opt =" document.createElement('option');" text =" machine;" machine = <%=machine%>'){
opt.selected = machine;
}
//just add another field and work with the default selection
else{
opt.value = machine;
}
try {
rselect.add(opt, null); // standards compliant; doesn't work in IE
}
catch(ex) {
rselect.add(opt); // IE only
}
}
}
}
//initilaize the variables on page load
var zselect = document.getElementById('database') ;
var zopt = zselect.options[zselect.selectedIndex]
${remoteFunction(controller: 'query', action: 'listmachines_ajax', params: '\'database=\' + zopt.value', onComplete: 'updateMachine(e)')}
we basically assume that our controller inject a variable with the name 'machine' on submitting the form. A controller closure could look like this:
def showTimeLine_ajax = {
assert params.database != null, "you need to provide the database in the params object"
assert params.machine != null, "you need to provide the machine in the params object"
def model = new HashMap()
//build our model, implementation not shown because of copyright
//model = buildModel(params.database,params.machine)
model.database = params.database
model.machine = params.machine
return model
}
and our form is simple enough
<g:form name="select_database_machine_form" method="post">
<g:select id="database" name="database" from="${dbs}" value="${database}"
onchange="${remoteFunction(
controller:'query',
action:'listmachines_ajax',
params:'\'database=\' + escape(this.value)',
onComplete:'updateMachine(e)')}"/>
<g:select id="machine" name="machine"/>
<g:submitToRemote action="showTimeLine_ajax" update="graph_content" value="execute query"/>
</g:form>
Tuesday, July 14, 2009
Groovy and Grails - why assert is great
Now there are different ways to check for this, the old and long java version:
if(params.get("myField") == null){
throw new RuntimeException("please provide the\"myField\" argument");
}
now the assert statement makes this a lot easier to read and saves code
assert params.myField != null. "please provide the \"myFiled\" argument"
now isn't this simpler?
Monday, July 13, 2009
SetupX - bug repository
The new setupx bug repository can now be found here
What's more expensive IN or BETWEEN statement
While doing this I discovered that the IN query cost slightly more than the BETWEEN query.
It's not a lot, but still something.
IN query:
explain select sample_name,class,date_of_import,date from samples where visible = 'TRUE' and sample_name like '%q%' and date in( '5/26/2009 12:00:00 AM', '6/11/2009 12:00:00 AM','5/26/2009 12:00:00 AM','2009-06-01 12:00:00 AM') order by 1 desc
result:
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Sort (cost=8126.07..8126.42 rows=139 width=37)
Sort Key: sample_name
-> Seq Scan on samples (cost=0.00..8121.12 rows=139 width=37)
Filter: (((sample_name)::text ~~ '%q%'::text) AND ((visible)::text = 'TRUE'::text) AND (date = ANY ('{"2009-05-26 00:00:00","2009-06-11 00:00:00","2009-05-26 00:00:00","2009-06-01 00:00:00"}'::timestamp without time zone[])))
4 record(s) selected [Fetch MetaData: 0/ms] [Fetch Data: 0/ms]
[Executed: 7/13/09 1:11:46 PM PDT ] [Execution: 2/ms]
BETWEEN query:
explain select sample_name,class,date_of_import,date from samples where visible = 'TRUE' and sample_name like '%q%' and date between '5/26/2009 12:00:00 AM' and '6/11/2009 12:00:00 AM' order by 1 desc
Result:
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Sort (cost=8123.15..8123.32 rows=67 width=37)
Sort Key: sample_name
-> Seq Scan on samples (cost=0.00..8121.12 rows=67 width=37)
Filter: (((sample_name)::text ~~ '%q%'::text) AND (date >= '2009-05-26 00:00:00'::timestamp without time zone) AND (date <= '2009-06-11 00:00:00'::timestamp without time zone) AND ((visible)::text = 'TRUE'::text))
4 record(s) selected [Fetch MetaData: 0/ms] [Fetch Data: 0/ms]
[Executed: 7/13/09 12:53:32 PM PDT ] [Execution: 2/ms]
Friday, July 10, 2009
OSX and SuperDuper - bug on raid systems
For some reason super duper cannot choose the active device to boot from, if it's a software raid. And it result's in a hanging system at boot.
Fix
go into system preferences before you boot and set your raid as the boot device. This should make it work.
Tested on
- raid 1 of 2 disks
- raid 0 of 4 disks (450mb/s transfer rate)
Thursday, July 9, 2009
Restoring OSX, backups are great
The wonderful timemachine software also did it's best to keep my backups up to date. So I never worried about a thing.
Till 2 harddrives started to report read/write errors 2 weeks ago. So I ordered a couple of new harddrives (500Gb x 4, I need speed and not space on this thing, and they are supposed to be nearly as fast as velicio raptors) To replace them.
At the time I noticed that I need more speed and 200mb/s write speed is just not fast enough for my stuff. So I decided to replace all 4 old harddrives with the 4 new ones in a raid 0 configuration.
I like to live risky? Sure, but I got backup's and timemachine is a great piece of software to restore a system...
Ok the idea was nice, but it turned out that you have to boot from the original osx cd to get timemachine to restore the complete system.
So plan B was on the table, let's call superduper to the rescue and use timemachine only for archiving my data.
Basically superduper generates a complete image of my system on an external harddrive and if my system fails, I can boot this HDD, keep working, while my system restores in the background.
And it only cost 27$ and makes live so much easier for me.
My new backup plan?
- hourly timemachine archives
- weekly super duper images
OSX and the Keyboard Pain
You also have to press the button before and during the 'boing'. And you need to keep it pressed!
Now I was thinking you could use just a windows Keyboard. But no it won't work reliable.
Now if you happen to own a wireless bluetooth apple keyboard, like I do. Be prepared to order a second wired keyboard to be able to execute commands before the OS is up.
Conclusion:
lame...
Mac OSX Boot options
Boot key combinations:
Everybody knows about some of these boot key combinations, but some of the more obscure combinations have been long forgotten (like how many of us have a Quadra AV and use a TV as a monitor!) – Check these out, you may need one of them someday!
- C : Forces most Macs to boot from the CD-Rom drive instead of the internal hard drive. Only works with Apple ROM drives and with bootable CD discs.
- D : Forces the first internal hard drive to be the startup disk.
- N : Netboot (New World ROM machines only) – Looks for BOOTP or TFTP Server on the network to boot from.
- R : Forces PowerBooks to reset their screen to default size (helpful if you’ve been hooked up to an external montior or projector!)
- T : Target Disk Mode (FireWire) – Puts machines with built-in FireWire into target Disk mode so a system attached with a FireWire cable will have that device show up as a hard drive on their system. Very useful for PowerBooks!
- Mouse Button Held Down : Ejects any mounted removable media.
- Shift : Disables all extensions (Mac OS 7-9), or disables Login items when using Mac OS X 10.1.3 or later. Also works when booting Classic mode up just like you were using the OS natively.
- Option : When using an Open Firmware "New World ROM" capable system, the System Picker will appear and query all mounted devices for bootable systems, returning a list of drives & what OS they have on them. On "Old World" systems the machine will simply boot into it’s default OS without any Finder windows open.
- Space bar : Brings up Apple’s Extension Manager (or Casady & Greene’s Conflict Catcher, if installed) up at startup to allow you to modify your extension set.
- Command-V : Boots Mac OS X into "Verbose Mode", reporting every console message generated during startup. Really shows what’s going on behind the scenes with your machine on startup!
- Command-S : Boots Mac OS X into "Single User Mode" – helpful to fix problems with Mac OS X, if necessary.
- Command-Option : Rebuilds the Desktop (Mac OS 7-9).
- Command-Option-P-R : Erases PRAM if held down immediately after startup tone. Your machine will chime when it’s erased the PRAM, most people will hold this combination for a total of 3 chimes to really flush the PRAM out.
- Command-Option-N-V : Erases NVRAM (Non-Volatile RAM). Used with later Power Macintosh systems mostly.
- Command-Option-O-F : Boots the machine into Open Firmware (New World ROM systems only).
- Command-Option-Shift-Delete : Forces your Mac to startup from its internal CD-ROM drive or an external hard drive. Very helpful if you have a 3rd party CD-ROM drive that is not an Apple ROM device.
- Command-Option-Shift-Delete-#(where #= a SCSI DEVICE ID) : Boot from a specific SCSI device, if you have your 3rd party CD-ROM drive set to SCSI ID 3, you would press "3" as the # in the combination.
And, the obscure ones :>) Older computers only, on some.
- Command-Option-I : Forces the Mac to read the disc as an ISO-9000 formatted disk
- Command : Boots with Virtual Memory turned off.
- Command-Option-T-V : Forces Quadra AV machines to use TV as a monitor.
- Command-Option-X-O : Forces the Mac Classic to boot from ROM.
- Command-Option-A-V : Forces an AV monitor to be recognized correctly.
Hacking SetupX - working on the sql tables instead of hibernate
So far the basic understanding is that the system has one major table and all queries are executed by building sub queries in it.
Advantage of the technique:
it's extremely flexible,
Disadvantage?
It's ridiculous slow and a nightmare to figure out, since you got so many possible sub graphs.
Don't we love reverse engineering an existing software?
So this is just a small collection of statements to get data out.
get list of available questions and attributes
select question from formobject group by question;
get the list of registered species
select value from formobject where question = 'species' group by value;
The final idea is to make a snapshot of the database every night and transform it into a real database structure. Like having several tables and so.
Ajax and Grails and YUI
So the first serious project is our quality control webfrontend which needs fancy stuff like
- progress bars
- multiple layers, cause they are hip...
So far one issue was to display a webpage in a layer on top of another webpage and the current soultion is:
controller:
class CompoundController {
/**
* shows the binbase compound
*/
def show_ajax = {
log.info("calling url...")
def id = params.id
def database = params.database
def server = System.getProperty("application.server")
def link = "http://${server}:8080/binbase-compound/bin/show/${id}?db=${database}"
//build our url
log.info("generated url: ${link}");
URL url = new URL(link)
InputStream stream = url.openStream()
Scanner scanner = new Scanner(stream)
//store the output, since this url can take a while to load, if it's not in the server cache
StringBuffer buffer = new StringBuffer()
while(scanner.hasNextLine()){
buffer.append(scanner.nextLine())
}
log.info("render result");
render "<iframe src="$%7Blink%7D" width="\"100%\"" height="\"100%\""></iframe>"
}
}
view:
<g:remotelink onloading="load();" oncomplete="done();" onsuccess="showFiles();" update="window_content" controller="compound" method="show_ajax" params="[database:database,id:id]">199651</g:remoteLink>
our div where we display the result
<div id="window">
<div class="hd"><div class="tl"></div><span></span><div class="tr"></div></div>
<div class="bd"><div id="window_content"></div></div>
</div>
and the related java script, yes I said it I'm using some javascript. Mostly the YUI library.
YAHOO.namespace("example.container");
function load() {
if (!YAHOO.example.container.wait) {
// Initialize the temporary Panel to display while waiting for external content to load
YAHOO.example.container.wait =
new YAHOO.widget.Panel("progress",
{
fixedcenter: true,
close: false,
draggable: false,
zindex:4,
modal: true,
visible: false
}
);
YAHOO.example.container.wait.setHeader("please wait, this process can take up to 5 minutes");
YAHOO.example.container.wait.render(document.body);
}
YAHOO.example.container.wait.show();
}
function done() {
YAHOO.example.container.wait.hide();
}
function showFiles() {
if (!YAHOO.example.container.files) {
// Initialize the temporary Panel to display while waiting for external content to load
YAHOO.example.container.files =
new YAHOO.widget.Panel("window",
{
fixedcenter: true,
close: true,
draggable: false,
zindex:5,
modal: false,
visible: false
}
);
//YAHOO.example.container.files.setHeader("Files for day...");
//YAHOO.example.container.files.setBody("<
div id=\"showFiles\">
<
/div>
");
YAHOO.example.container.files.render(document.body);
}
YAHOO.example.container.files.show();
}
and than there is some css,
#window.yui-panel .bd {
overflow: hidden;
padding: 0px;
border: 1px solid #aeaeae;
background-color: #FFF;
width:1024px;
height:600px;
}
#window.yui-panel .ft {
font-size: 75%;
color: #666;
padding: 0px;
overflow: hidden;
border: 1px solid #aeaeae;
border-top: none;
background-color: #dfdfdf;
}
#window.yui-panel .hd span {
vertical-align: middle;
line-height: 22px;
font-weight: bold;
}
#window.yui-panel .hd .tl {
width: 7px;
height: 22px;
top: 0;
left: 0px;
position: absolute;
}
#window.yui-panel .hd .tr {
width: 7px;
height: 22px;
top: 0;
right: 0px;
position: absolute;
}
#progress.yui-panel .bd {
overflow: hidden;
padding: 0px;
margin: 5px;
background-color: #FFF;
}
#progress.yui-panel .ft {
font-size: 75%;
color: #666;
padding: 0px;
overflow: hidden;
border: 1px solid #aeaeae;
border-top: none;
background-color: #dfdfdf;
}
/* Provide skin for custom elements */
#progress.yui-panel .hd span {
vertical-align: middle;
line-height: 22px;
font-weight: bold;
padding-left: 60px;
padding-right: 60px;
padding-top: 30px;
padding-bottom: 30px;
border: 1px solid #aeaeae;
background-color: #dfdfdf;
width: 120px;
height: 60px;
}
#progress.yui-panel .hd .tl {
width: 7px;
height: 22px;
top: 0;
left: 0px;
position: absolute;
}
#progress.yui-panel .hd .tr {
width: 7px;
height: 22px;
top: 0;
right: 0px;
position: absolute;
I'm still not a fan of css/js, but sometimes you gotta use what's available.
MockingSpring - Testing ServletFiltes
well it's hot in davis and I have no AC, so what's better than to run into the nice and cold office and playing with some junit tests.
Basically how to junit test servlet filters. Like always somebody smart wrote some great tools for me to use.
An example of a simple servlet filter which forwads all access to a cutom report factory
package edu.ucdavis.genomics.metabolomics.binbase.filter;
import edu.ucdavis.genomics.metabolomics.util.status.Report;
import edu.ucdavis.genomics.metabolomics.util.status.ReportFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import org.apache.log4j.Logger;
/**
* forwards all requests to the reporter which deals with it
*
* User: wohlgemuth
* Date: Jun 28, 2009
* Time: 3:33:00 PM
*/
public class IPLogger implements Filter {
/**
* forwards everything to the server
*/
private Report report;
/**
* logging nstances
*/
private Logger logger = Logger.getLogger(getClass().getName());
/**
* initialize the connection to the report method
*
* @param filterConfig
* @throws ServletException
*/
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("initialize filter");
//access the factory we need for the reporter
String factory = filterConfig.getInitParameter("factory");
if (factory == null) {
logger.info("no factory provided, so we use the default factory");
report = ReportFactory.newInstance().create(IPLogger.class.getSimpleName());
} else {
logger.info("using factory: " + factory);
report = ReportFactory.newInstance(factory).create(IPLogger.class.getSimpleName());
}
}
/**
* does the actual filtering
*
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String host = servletRequest.getRemoteHost();
String address = servletRequest.getRemoteAddr();
int port = servletRequest.getRemotePort();
String uri = "unknown";
if (servletRequest instanceof HttpServletRequest) {
HttpServletRequest req = (HttpServletRequest) servletRequest;
uri = req.getRequestURI();
}
//send it out so that we can deal with these event in a different class or so
report.report(new IPRequest(host, uri, address, port), FilterReports.FITLER_URI_ACCESS, FilterReports.FILTER_REQUEST);
}
public void destroy() {
}
}
and the junit test to test it, without a web server or so.
public class IPLoggerTest {
private IPLogger filter;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private MockFilterChain chain;
@Before
public void setUp() throws Exception {
filter = new IPLogger();
MockFilterConfig config = new MockFilterConfig();
config.addInitParameter("factory", TestFactory.class.getName());
filter.init(config);
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
chain = new MockFilterChain();
}
@After
public void tearDown() throws Exception {
}
@Test
public void testDoFilter() throws IOException, ServletException {
request.setRequestURI("http://127.0.0.1/test.html");
filter.doFilter(request, response, chain);
}
}
and our little factory which does the acutal testing of the received object
public class TestFactory extends ReportFactory{
private Logger logger = Logger.getLogger(getClass());
/**
* checks if all the result's fit the exspectations
*
* @param properties
* @param s
* @return
*/
public Report create(Properties properties, String s) {
return new Report() {
public void report(String s, Serializable serializable, ReportEvent reportEvent, ReportType reportType, String s1, Date date, Exception e) {
logger.info("received: " + serializable);
assertTrue(reportEvent.equals(FilterReports.FITLER_URI_ACCESS));
assertTrue(reportType.equals(FilterReports.FILTER_REQUEST));
assertTrue(serializable instanceof IPRequest);
IPRequest request = (IPRequest) serializable;
assertTrue(request.getHost().equals("localhost"));
assertTrue(request.getUri().equals("http://127.0.0.1/test.html"));
assertTrue(request.getAddress().equals("127.0.0.1"));
assertTrue(request.getPort() == 80);
}
public String getOwner() {
return IPLogger.class.getSimpleName();
}
};
}
}
Grails and some annoying CSS in the Body Part
So long story short, for some reason grails defines several body elements in the main.css file
body {
background: #cccccc;
color: #333;
font: 11px verdana, arial, helvetica, sans-serif;
width:100%;
height:100%;
}
.body {
float: left;
margin: 0 15px 10px 15px;
}
and the 'float:left' in the second body tag wrecked havoc with my application...
...great 3 days wasted on lay outing...
Creating a minimum and a maximum Date for a Calendar
For example I needed the minimum and maximum date for a day. After a lot of googleling I came up with a simple? solution.
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.set(Calendar.AM_PM,Calendar.AM);
c1.set(Calendar.HOUR, c1.getActualMinimum(Calendar.HOUR));
c1.set(Calendar.MINUTE, c1.getActualMinimum(Calendar.MINUTE));
c1.set(Calendar.SECOND, c1.getActualMinimum(Calendar.SECOND));
c1.set(Calendar.MILLISECOND, c1.getActualMinimum(Calendar.MILLISECOND));
c2.set(Calendar.AM_PM,Calendar.PM);
c2.set(Calendar.HOUR, c2.getActualMaximum(Calendar.HOUR));
c2.set(Calendar.MINUTE, c2.getActualMaximum(Calendar.MINUTE));
c2.set(Calendar.SECOND, c2.getActualMaximum(Calendar.SECOND));
c2.set(Calendar.MILLISECOND, c2.getActualMaximum(Calendar.MILLISECOND));
Date first = c1.getTime();
Date last = c2.getTime();
Result:
Tue Jul 07 00:00:00 PDT 2009
Tue Jul 07 23:59:59 PDT 2009
The important part is here:
c1.set(Calendar.AM_PM,Calendar.AM);
if you don't specify AM/PM you end up with:
Tue Jul 07 12:00:00 PDT 2009
which is a bit annoying...
Installing SetupX under ubuntu
how to:
- install your plain old Ubuntu server box
- install java 5: apt-get install sun-java5-jdk
- install subversion: apt-get install subversion
- install unzip: apt-get install unzip
- install ant: download ant 1.6.5, unzip it and add it to the path
- install jboss: download jboss-4.2.3.GA, unzip it in your directoy of choice, let's use opt
- get setupX:
svn checkout -r421 http://setupx.googlecode.com/svn/trunk/ /opt/setupx
- install mysql: apt-get install mysql-server
- start the mysql server: /etc/init.d/mysql start
- lims/setup/setup.properties - general configuration
- lims/setup/resources/system/config.properties - configure where jboss sits
- lims/setup/resources/system/system.properties - configure email settings and jboss again. Also specify your data directories
- go into /opt/jboss/seupx/lims
- execute 'sh firstinstall.sh'
[java] Util_____________: DEBUG: Using org.xml.sax.parser : org.apache.xerces.parsers.SAXParser
[java] org.setupx.repository.SettingsUnavailableException: java.io.FileNotFoundException: /usr/share/setupx/lims/conf/system/system.properties (No such file or directory)
This is directly related to a bug in the class "org.setupx.repository.Settings" and can be fixed with a simple change in this file to reflect our directory.
This is a nice example why it's considered to be bad practice to hard code file paths.
private static File file = new File("/opt/setupx/lims/conf/system/system.properties");
Since we already created the database with the 'firstinstall.sh' script we now just need to go into setupx/lims/setup and execute:
sh setup.sh
After the installation finished we could now access setupX under:
http://****:8080/xx1/
your setupx username is the set email address and your password the same.
review:
The installation took a lot of effort to get it working and is not yet perfect. I think the first thing which should be done is to write a graphical ant installer which modifies the files for you, to make this process a bit easier.
The main issue is really the absolute file path in the one java class.
Time cost: a bit over an hour and 30 minutes.