tag:blogger.com,1999:blog-73180417601321050982024-03-12T17:51:22.414-07:00Igor Polevoy BlogIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.comBlogger20125tag:blogger.com,1999:blog-7318041760132105098.post-43324429504643380972012-07-30T12:30:00.001-07:002015-11-29T20:54:16.676-08:00Defend against SQL Injection using ActiveJDBC<br />
I was asked on forums <a href="https://groups.google.com/forum/?hl=en#!topic/activejdbc-group/5D2jhWuW4Sg">how ActiveJDBC defends against SQL Injection attacks</a>. My first reaction was: hey, this is not an ORM problem, talk to web devs :)<br />
Luckily, <a href="http://blog.jooq.org/2012/07/29/database-abstraction-and-sql-injection/">Lukas Eder wrote a nice blog</a> that helped put things into perspective. While SQL Injection attacks are not the task of ORMs per se, ORMs still need to provide some level of advice on how to deal SQL injection pitfalls.<br />
Lukas even offered some actual code snippets on his article. What is a developer to do to try things out? HE/she writes tests, and so I proceeded to write a test using some of the examples of his code.<br />
The first test had this code:<br />
<br />
<pre><code><pre style="background-color: white; font-family: 'DejaVu Sans Mono';"><pre style="font-family: 'DejaVu Sans Mono';"><pre style="font-family: 'DejaVu Sans Mono';"><span style="font-size: x-small;">String id = <span style="color: green; font-weight: bold;">"1';drop table users;select * from people where name = 'John"</span>;
List<User> users = User.<span style="font-style: italic;">where</span>(<span style="color: green; font-weight: bold;">"id = '" </span>+ id + <span style="color: green; font-weight: bold;">"'"</span>);
users.size();
User user1 = <span style="color: navy; font-weight: bold;">new </span>User();
user1.set(<span style="color: green; font-weight: bold;">"first_name"</span>, <span style="color: green; font-weight: bold;">"John"</span>, <span style="color: green; font-weight: bold;">"last_name"</span>, <span style="color: green; font-weight: bold;">"Doe"</span>,
<span style="color: green; font-weight: bold;"> "email"</span>, <span style="color: green; font-weight: bold;">"john@doe.com"</span>).saveIt();
User.<span style="font-style: italic;">findAll</span>().dump();</span></pre>
</pre>
</pre>
</code></pre>
At first when I tried this against MySQL, I got "invalid statement" exception, apparently it could not handle the semicolon in the middle of the statement. After that, I ran this same code against H2 database, and sure enough, the SQL injection worked. This resulted in an exception:<br />
<br />
<br />
<span style="color: red; font-family: "courier new" , "courier" , monospace;"><span style="background-color: yellow;">Caused by: org.h2.jdbc.JdbcSQLException: Table "USERS" not found; SQL statement:</span></span><br />
<span style="color: red; font-family: "courier new" , "courier" , monospace;"><span style="background-color: yellow;">INSERT INTO users (email, first_name, last_name) VALUES (?, ?, ?) [42102-171]</span></span><br />
<span style="color: red; font-family: "courier new" , "courier" , monospace;"><span style="background-color: yellow;"><br /></span></span>
<b>Holy crap! My table USERS is gone!</b><br />
<b><i><br /></i></b>
This is bad news for those people who use a simple string concatenation to make SQL statements in public facing web projects.<br />
<br />
However, I quickly wrote a second test that uses dynamic parameters passed to a model:<br />
<br />
<pre style="background-color: white; font-family: 'DejaVu Sans Mono';"><pre style="font-family: 'DejaVu Sans Mono';"><span style="font-size: x-small;"><span style="background-color: #e4e4ff;">String</span> id = <span style="color: green; font-weight: bold;">"1';drop table users;select * from people where name = 'John"</span>;
List<User> users = User.<span style="font-style: italic;">where</span>(<span style="color: green; font-weight: bold;">"id = ?"</span>, id);
users.size();
User user1 = <span style="color: navy; font-weight: bold;">new </span>User();
user1.set(<span style="color: green; font-weight: bold;">"first_name"</span>, <span style="color: green; font-weight: bold;">"John"</span>, <span style="color: green; font-weight: bold;">"last_name"</span>, <span style="color: green; font-weight: bold;">"Doe"</span>,
<span style="color: green; font-weight: bold;"> "email"</span>, <span style="color: green; font-weight: bold;">"john@doe.com"</span>).saveIt();
User.<span style="font-style: italic;">findAll</span>().dump();</span></pre>
<span style="background-color: transparent;"><span style="font-size: x-small;">
</span>As you can see here, the only difference is that I pass the "name" parameter as a dynamic one, instead of simply concatenating strings</span>
</pre>
<br />
The output from this test is:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">Model: org.javalite.activejdbc.test_models.User, table: 'users', attributes: {EMAIL=john@doe.com, FIRST_NAME=John, ID=1, LAST_NAME=Doe}</span><br />
<br />
As you can see, the table USERS is intact, no harm is done.<br />
<br />
So, what is the take out from here? String concatenation to build dynamic queries in web applications is evil!<br />
<br />
<b>But, since ActiveJDBC uses <a href="http://docs.oracle.com/javase/6/docs/api/java/sql/PreparedStatement.html">PreparedStatement</a>, you are safe as long as you use dynamic parameters instead of splicing strings together. </b><br />
<br />
I actually never use string concatenation, not because I constantly worry about SQL Injection attacks, but simply because this makes for some ugly spaghetti code and this probably one of the reasons I did not pay much attention to it before.<br />
<br />
Cheers to safe coding!<br />
<div>
<br /></div>
Igor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com2tag:blogger.com,1999:blog-7318041760132105098.post-51197561332427882422012-04-08T22:50:00.001-07:002012-04-26T18:33:11.045-07:00Just how thin can a framework be? ActiveJDBC vs Hibernate.When people talk about thickness of a framework, and it being lightweight, what do they actually mean?<br />
<br />
I think there needs to be a few parameters to be looked at, for instance: <br />
<ul>
<li>Level of intrusiveness into your code (subjective)</li>
<li>Speed of execution (objective)</li>
<li>Code elegance (subjective)</li>
<li>Physical weight - total size of dependencies for "Hello world" (objective)</li>
<li>Stack depth (objective) - depth of a stack in case of exception coming from a lower level technology</li>
</ul>
<br />
Lets consider the <b>level of intrusiveness</b> with Hibernate and ActiveJDBC. I personally of course prefer ActiveJDBC because it has almost no annotations, no configuration files, but most of all it has no third party object such as Hibernate Session that actually operates on entites. <br />
<br />
Here is a code in Hibernate entity:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">@Table(name = "employees")</span><br />
<span style="font-family: "Courier New",Courier,monospace;">public class Employee implements Serializable {</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> public Employee() {</span><span style="font-family: "Courier New",Courier,monospace;">}</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> @Id</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> @Column(name = "id")</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> @GeneratedValue</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> Integer id;</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> @Column(name = "first_name")</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> String firstName;</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> public Integer getId() {</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return id;</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> }</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> public void setId(Integer id) {</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> this.id = id;</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> }</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> public String getFirstName() {</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return firstName;</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> }</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> public void setFirstName(String firstName) {</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> this.firstName = firstName;</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> }</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> @Override</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> public String toString() {</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return "Employee{" +</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> "id=" + id +</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> ", first_name='" + firstName + '\'' +</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> '}';</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> }</span><br />
<span style="font-family: "Courier New",Courier,monospace;">}</span><br />
<br />
<br /><br />
Usage of entity:<br />
<div style="font-family: "Courier New",Courier,monospace;">
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();</div>
<div style="font-family: "Courier New",Courier,monospace;">
Session session = sessionFactory.openSession(); </div>
<span style="font-family: "Courier New",Courier,monospace;">List</span><employee><span style="font-family: "Courier New",Courier,monospace;"> employees = session.createQuery("select e from Employee as e").list();</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> session.close();</span><br />
<br />
And here is comparable code in ActiveJDBC:<br />
<br />
Model:<br />
<span style="font-family: "Courier New",Courier,monospace;">public class Employee extends Model{}</span><br />
<br />
That is right! One line of code, and nothing else.<br />
<br />
Usage of model:<br />
<span style="font-family: "Courier New",Courier,monospace;">Base.open("com.mysql.jdbc.Driver", "jdbc:mysql://localhost/test_db", "user1", "*****");</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> List</span><employee><span style="font-family: "Courier New",Courier,monospace;"> employees = Employee.findAll();</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> Base.close();</span><br />
<br />
As you can see, ActiveJDBC uses a different paradigm: models (entities in AJ talk) operate <br />
on self, without requiring a third party class. <br />
<br />
I think that by code intrusiveness, ActiveJDBC is certainly thinner than Hibernate. <br />
<br />
<b>Speed of execution</b>: I built a simple non-scientific test in both ActiveJDBC and Hibernate. <br />
The code inserts 50 thousand records into MySQL table, then reads all 50K records from it. <br />
This is performed on my laptop, which is: MBP 2009, Core 2 Duo CPU P8700 @ 2.53GHz, <br />
with 8G RAM, 256G SSD and Ubuntu running natively.<br />
Hibernate insert: 16057 milliseconds<br />
ActiveJDBC insert: 9630 milliseconds<br />
<br />
Hibernate select: 50000 records in: 1874 milliseconds<br />
ActiveJDBC select: 50000 records in: 836 milliseconds<br />
<br />
As you can see, ActiveJDBC is significantly faster given exactly the same task:<br />
Insert: ActiveJDBC took 40% less time.<br />
Select:ActiveJDBC took 54% less time. <br />
<br />
<b>Code elegance:</b> while this is super subjective especially considering the fact that I'm the author of ActiveJDBC API, I hope most people will agree with me simply by looking at code above. <br />
<br />
<b>Physical weight: </b>This is a total size of all dependencies a simple application requires. <br />
Here ActiveJDBC wins hands down.<br />
ActiveJDBC dependencies:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">-rw-r--r-- 1 igor igor 137026 2012-04-05 12:03 activejdbc-1.2-SNAPSHOT.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 33795 2012-04-05 12:03 javalite-common-1.2-SNAPSHOT.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 495944 2012-04-05 12:03 mysql-connector-java-5.0.4.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 23659 2012-04-05 12:03 slf4j-api-1.5.10.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 7599 2012-04-05 12:03 slf4j-simple-1.5.10.jar</span><br />
<br />
Total size: 704K<br />
<br />
Hibernate dependencies:<br />
<span style="font-family: "Courier New",Courier,monospace;">-rw-r--r-- 1 igor igor 443432 2012-04-05 12:13 antlr-2.7.6.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 26361 2012-04-05 12:13 asm-1.5.3.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 16757 2012-04-05 12:13 asm-attrs-1.5.3.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 282338 2012-04-05 12:13 cglib-2.1_3.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 175426 2012-04-05 12:13 commons-collections-2.1.1.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 38015 2012-04-05 12:13 commons-logging-1.0.4.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 313898 2012-04-05 12:13 dom4j-1.6.1.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 208048 2012-04-05 12:13 ehcache-1.2.3.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 2321639 2012-04-05 12:13 hibernate-3.2.7.ga.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 365546 2012-04-05 12:13 hibernate-annotations-3.5.6-Final.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 66426 2012-04-05 12:13 hibernate-commons-annotations-3.0.0.ga.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 2566731 2012-04-05 12:13 hibernate-core-3.5.6-Final.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 100884 2012-04-05 12:13 hibernate-jpa-2.0-api-1.0.0.Final.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 8812 2012-04-05 12:13 jta-1.0.1B.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 495944 2012-04-05 12:13 mysql-connector-java-5.0.4.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 52150 2012-04-05 12:13 persistence-api-1.0.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 22338 2012-04-05 12:13 slf4j-api-1.5.6.jar</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> -rw-r--r-- 1 igor igor 7583 2012-04-05 12:13 slf4j-simple-1.5.6.jar</span><br />
<br />
Hibernate requires a whopping 7424K, more than 10 times of ActiveJDBC! Even if I remove MySQL driver, this comparison is still not in favour of Hibernate. <br />
<br />
<b> Stack depth</b>: this is simply counting methods on the stack trace, which gives you a pretty good idea of a framework depth. In order to see this for ORM, I mangled the SQL to cause an exception in the DB layer, and here are results:<br />
<br />
Hibernate depth: <br />
<span style="font-family: "Courier New",Courier,monospace;"> 1276 [main] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1054, SQLState: 42S22</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> 1276 [main] ERROR org.hibernate.util.JDBCExceptionReporter - Unknown column 'age' in 'where clause'</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> Exception in thread "main" <span style="background-color: yellow;">org.hibernate.exception.SQLGrammarException: could not execute query</span></span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.loader.Loader.doList(Loader.java:2536)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.loader.Loader.list(Loader.java:2271)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:452)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:363)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1268)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at hibernate_test.SelectAllHibernate.main(SelectAllHibernate.java:13)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at java.lang.reflect.Method.invoke(Method.java:597)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> Caused by: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown column 'age' in 'where clause'</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:936)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2870)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1573)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1665)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.Connection.execSQL(Connection.java:3176)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1153)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1266)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at <span style="background-color: yellow;">org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)</span></span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.loader.Loader.getResultSet(Loader.java:1953)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.loader.Loader.doQuery(Loader.java:802)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.hibernate.loader.Loader.doList(Loader.java:2533)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> ... 13 more</span><br />
<br />
<br />
ActiveJDBC depth:<br />
<span style="font-family: "Courier New",Courier,monospace;">Exception in thread "main" org.javalite.activejdbc.DBException: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> syntax to use near 'where age > 1' at line 1, Query: SELECT * FROM employees WHERE where age > 1</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:936)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2870)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1573)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1665)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.Connection.execSQL(Connection.java:3176)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1153)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1266)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.javalite.activejdbc.DB.find(DB.java:408)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.javalite.activejdbc.LazyList.hydrate(LazyList.java:304)</span><br style="background-color: yellow; font-family: "Courier New",Courier,monospace;" /><span style="background-color: yellow; font-family: "Courier New",Courier,monospace;"> at org.javalite.activejdbc.LazyList.size(LazyList.java:454)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at activejdbc_test.SelectAllActiveJDBC.main(SelectAllActiveJDBC.java:13)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at java.lang.reflect.Method.invoke(Method.java:597)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> Caused by: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> that corresponds to your MySQL server version for the right syntax to use near 'where age > 1' at line 1</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> ... 16 more</span><br />
<br />
<br />
When you count the number of lines in exception stack trace betwen the client code (your code) and low level technology<br />
(MySQL in this case), you will have an idea of a framework depth. For ActiveJDBC it is 3, for Hibernate it is 15. <br />
So, Hibernate is about 5 times thicker than ActiveJDBC. <br />
<br />
One might say: so what, why do I care about the size of dependencies, depth of stack trace, etc. I think a good developer <br />
should care about these things. The thicker the framework, the more complex it is, the more memory it allocates, <br />
the more things can go wrong. Besides, simply by requiring certain dependencies, it can limit your options <br />
of using up to date versions of the same dependencies, creating headaches on classpath. <br />
<br />
Bottom line is: choose your frameworks wisely<br />
<br />
cheers</employee></employee>Igor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com32tag:blogger.com,1999:blog-7318041760132105098.post-52800120173032801932011-09-12T22:37:00.000-07:002011-09-12T22:53:09.017-07:00ActiveJDBC cascades deep and shallowEach ORM adds functionality not found in standard DB access layer, and <a href="http://code.google.com/p/activejdbc/">ActiveJDBC</a> is no exception. Lets say delete with cascade. Method:<br />
<pre class="brush: java;">model.deleteCascade();</pre>has been in existence for a while, but had somewhat limited functionality. It deleted the model and its immediate children in case One to Many and Polymorphic associations. In case of Many to Many, it was merely clearing links in a join table. The main reason for this was performance. In order to implement a true cascade delete, an ORM must follow all relationships until none left, but unfortunately in the process, it has to load every record instance into memory. This process might allocate huge chunks of memory and generate unexpected number of DELETE statements to the database. <br />
<p>So, initially performance considerations stopped me from implementing a true cascade delete. After all, deleting immediate children is very efficient: clean all of them in one SQL, then delete the parent. <br />
</p><p>However, once people started using <a href="http://code.google.com/p/activejdbc/">ActiveJDBC</a>, many asked a question: "this deleteCascade() is not really cascading, what the heck?" (well, they are all nice people, but I need to add some drama here keep you reading:)).<br />
In any case, they pointed out inconsistencies of a name and the actual semantics. This prompted me to implement delete cascade true to its name. So, a new version just published to Sonatype will cascade like there is no tomorrow. It will navigate all child and many to many relationships of a model being deleted, find their children, grand children, grand-grand kinds, etc. No one walks out alive, if you know what I mean:)<br />
<br />
Implications might be strange at first, but logical if you think about it. Imagine you have a relationship where doctors treat patients and patients visit doctors. In other words, this is a many to many relationship. If you delete a doctor, then all patients associated to that doctor are also deleted. But, what if a patient also visits another doctor? Guess what, that doctor is also deleted (because it is a dependency of a patient being deleted) and so are his/her patients, and so on. So, "deleteCascade()" really knows how to cascade!<br />
<br />
<p>But, what about the fast and efficient delete if all I want is to delete a model and immediate children (assuming no grand kids)? For that, there is a new method:<br />
<br />
<pre class="brush: java;">model.deleteCascadeShallow();</pre>which retained the same functionality <code>deleteCascade()</code> had before. <br />
<br />
So, deleting models in <a href="http://code.google.com/p/activejdbc/">ActiveJDBC</a> is an easy business, with methods:<br />
<pre class="brush: java;">delete();
deleteCascade();
deleteCascadeShallow();
</pre><br />
For more detailed info, see this Wiki page: <a href='http://code.google.com/p/activejdbc/wiki/DeleteCascade'>http://code.google.com/p/activejdbc/wiki/DeleteCascade</a><br />
<br />
cheers..Igor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com2tag:blogger.com,1999:blog-7318041760132105098.post-70873976427581900302011-07-24T01:42:00.000-07:002011-10-01T01:12:45.107-07:00Stop hating Java 2This post is in response to <a href="http://andrzejonsoftware.blogspot.com/2011/07/stop-hating-java.html">Andrzej on Software/ Stop hating Java</a> post. I support most of the ideas Andrzej expressed in that post. Think of this post as continuation. This is my brain dump on things that was sitting somewhere in the back of my mind for some time and Andrzej's post jolted it out. <br />
<br />
<b>Ruby developers are prone to cults (observation). </b><br />
It is interesting to see that Ruby developers (most people I worked with are good smart guys) seem to have all drank several cool-aids: Ruby/Rails/Apple MBPs/IPhones/TextMate. They are "green", look to be "democratic", wear sloppy clothes, and are "laid back". They certainly fall into a few stereotypical descriptions. They religiously follow another big gorilla (Apple), whose policies are even more tight than that of Microsoft. What is more interesting is that we were able to pinpoint a Ruby developer in a group photo shot! Overall, I'd say because Ruby developers are prone to cult-like behavior, they miss a bigger picture sometimes. For them if it is not Ruby, it must be crap. Ruby developers are sometimes categorical to the extend bordering adolescent behavior. I think it is generally a human thing to resists other peoples' opinions and change. (note to self: Ruby developers are humans :)). <br />
<br />
<b>Any platform will do</b><br />
Most people dislike languages they do not use, and Ruby developers are not exception. However, any language/platform can be used to build excellent piece of software, and there are many examples of that. Most all (as someone mentioned on Andrzej's post comments) think that PHP is crap, but although I'm not a PHP developer, I enjoyed this post from MailChimp, who has proven that if you have a brain you can build a great system ... even in PHP:) - <a href="http://blog.mailchimp.com/ewww-you-use-php/">http://blog.mailchimp.com/ewww-you-use-php/</a><br />
<br />
<b>How Java screwed up royally</b><br />
<ul><li>Standards - the biggest flop in the Java history was Java Enterprise. This does not require any explanation, I hope. Standards are a plague of Java. They are designed to make different implementations together, but this is not happening. Instead, they take years to "standardize", when Internet years are even shorter than dog years. There is a handful of low level good standards: JDBC, Servlets, JMS, but the rest is just a waste of time.</li>
<li>Trying to circumvent standards - Spring/XML mess. Spring came to mass market some time in 2003, and spread like wild fire (due to complexity of JEE). I personally do not like Spring and try to avoid it at all costs (same goes for JEE). Spring projects are messy, impossible to debug, and tend to grow like a cactus: in all directions. </li>
<li>Way of thinking that if you have a hammer(Spring/XML) in your hand, every problem looks like a nail (your project). </li>
<li>Popularity of Java sucked a lot of people into the Java world who should not be there (maybe they should not even be in IT in general). I'd argue that when (if ever) Ruby becomes as popular, it will get all the problems Java has: boring business applications, millions of lines of unmaintainable legacy code, army of non-talented and non-passionate developers, corporate culture, heavy management, etc. </li>
<li>Java developers are ostriches - they keep their heads in the Java sand and are afraid to look around.</li>
</ul><b>Ruby would be in obscurity if not for Rails</b><br />
Ruby developers say they have things other than Rails. I'd say this is BS. All things non-Rails came about to support Rails in one form or another. I think that Rails undoubtedly made Ruby famous. Rails is a Ruby killer application. Ruby is actually older than Java by a year or two, but has been in obscurity all these years until Rails came along. If it were possible to predict a different past, I'd say that if DHH used PHP for his projects and never wrote Rails, the world as we know it would associate the word ruby with a precious stone, rather than a programming language.<br />
<br />
<b>My History of Rails experience</b><br />
I worked on a website project for Sears that was all Java, but slowly became a blend of Java and Rails. When this was happening, the project was joined by a number of good Ruby developers. While we had disagreements and arguments, I adopted a strategy to learn as much as I could from these folks, and about Ruby/Rails thing. As it turned out, there was much to learn and so I did. In the process, I also saw that many good things in Rails can certainly be implemented in Java, to the benefit of Java community. <br />
<br />
<b>What I did to make Java developers happier</b><br />
Needless to say, I like Rails for its productivity and think that the Rails way of conventions and style of web development is(was) better than anything I knew in Java. So, I waited for someone to do cross-pollination and implement these ideas in Java. And then I waited some more. After a 2 - 3 year wait, I realized this is not happening, and decided to take the initiative in my hands. I wrote <a href="http://code.google.com/p/activejdbc/wiki/JSpec">JSpec</a> with DSL similar that of RSpec, <a href="http://code.google.com/p/activejdbc/">ActiveJDBC</a> - implementation of ActiveRecord in Java, and <a href="http://code.google.com/p/activeweb/">ActiveWeb</a> - dynamic web framework similar to Rails. I manage a team of 10 developers and we have a mixed environment Rails/<a href="http://code.google.com/p/activeweb/">ActiveWeb</a>/<a href="http://code.google.com/p/activejdbc/">ActiveJDBC</a> and about 10 commercial websites/batch applications. All new sites are built with Active* stuff, and I can attest that developer productivity in Java are the same as using Rails. <br />
<br />
<b>What I seriously miss in Java</b><br />
Closures! Of all the stupid useless language features that Sun has been adding for years (generics for instance - only a madman can understand their syntax), they <br />
missed the boat with closures, the one and only feature I genuinely miss. Closures certainly would make all the callbacks and stupid inner anonymous classes go away - and this will be the biggest contribution to making Java more readable. IN addition, closures would make most Java APIs concise and easy to use, as Groovy has already done by adding a ton of methods to JDK classes.<br />
<br />
<b>Message to haters</b><br />
It seems that people who start sentences with: "I hate..." have constipation or something. My advice: take some Metamucil, after that a few beers with friends, and then surprise people you know by always starting with: "I like ...".<br />
<br />
<b>Conclusion</b><br />
Whew, if you are reading this sentence, you are one patient person! All these Java vs Ruby vs .NET vs PHP [plug your abbreviation here] discussions are water under bridge. People call Java Cobol of the day. I'd say that if a Java program runs a business for 30 - 40 years, it is a huge success. Who knows what languages we will be using 30 - 40 years from now? So far, we have a good selection, let's enjoy!Igor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com25tag:blogger.com,1999:blog-7318041760132105098.post-27051344232953721182011-04-18T17:24:00.000-07:002011-04-27T18:08:19.452-07:00What is good for Ruby is good for Java: JSpecPeople familiar with Ruby will invariably learn RSpec. RSpec is a great library for writing specifications, or specs as Ruby developers call them. Some time ago, I developed JSpec somewhat modeled after RSpec. I needed a better language for writing expectations. What is an expectation and how is it different from assertion?<br />
<br />
In a Java tests, people usually use assertions to check conditions after some code is executed, such as:<br />
<br />
<pre class="brush: java;">assertEquals(stirng1, string1); </pre><br />
In the case above if string1 and string2 are not equal, the assertion fails thus failing the test. In general, having a test is much better than not having one, but after learning RSpec, I really felt that the asserts are inadequate.<br />
Asserts are an old way of saying: "<b>I have developed code, and I will check that it works</b>". I <i><b>really prefer</b></i> a more modern TDD/BDD approach that says: "<b>I captured requirements of a system in test code, and will implement it after</b>". This allows me to develop the implementation of my system <i>after</i> I write a specification. There is so much written on the virtues of good TDD/BDD development. Those interested should at least watch this: <a href="http://www.videosurf.com/video/beyond-test-driven-development-behaviour-driven-development-103819366?vlt">Dave Astels BDD presentation</a>.<br />
<br />
As part of the work I did while working on <a href="http://code.google.com/p/activejdbc">ActiveJDBC</a> , I developed the JSpec library.<br />
The main idea is to replace "assert" language with "should" language and make it as close to English as possible. This forces the brain to work in a different mode, writing a "specification of behavior" for your program rather than "assertion" that the program works. The difference might seem subtle, but requires a different style of thinking and promotes true TDD/BDD - when specifications are written before implementation, sometimes even by different people. <br />
<br />
Here is an example of "standard" JUnit code:<br />
<pre class="brush: java;">@Test
public void testCalculator(){
Calculator c = new Calculator();
c.add(2, 2);
assertEquals(c.result(), 4);
}
</pre>and here is the same written in JSpec (also with JUnit):<br />
<pre class="brush: java;">@Test
public void shouldAddNumbersCorrectly(){
Calculator c = new Calculator();
c.add(2, 2);
a(c.result()).shouldBeEqual(4);
}
</pre><br />
As you can see, the difference is subtle, but profound. More information on the use of this library can be found here: <a href="http://code.google.com/p/activejdbc/wiki/JSpec">http://code.google.com/p/activejdbc/wiki/JSpec</a><br />
<br />
<br />
happy coding!<br />
igorIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com1tag:blogger.com,1999:blog-7318041760132105098.post-31501094375626481742011-04-14T20:27:00.000-07:002011-04-16T09:52:01.656-07:00An easier GWT starter projectGWT is a powerful technology for Rich Internet Applications (RIA), hands down more powerful than anything else I know that can produce quality JavaScript. It comes with a simple script to generate new projects called <span style="font-family: "Courier New",Courier,monospace;">webAppCreator</span>. You would think that this will create a simple project structure you can then enhance and call your own, right? Kinda...<br />
<br />
The product of this script is a working application with a server round trip that shows the power and simplicity of GWT RPC. Unfortunately, this project is chock full of comments and unnecessary code so much, that it is hard to see trees behind forest! I cleaned this many times to figure out simple things, but this time decided to drop it into the blogo-sphere so that other people could benefit as well.<br />
<br />
I was able to reduce the amount of code to about 1/4th of the original, leaving the same functionality in place.<br />
<br />
Here is the link: <a href="http://igorpolevoy.com/public/attach/GWT/test.zip">http://igorpolevoy.com/public/attach/GWT/test.zip</a><br />
enjoy<br />
igorIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com0tag:blogger.com,1999:blog-7318041760132105098.post-85458926971593331712011-02-01T15:59:00.000-08:002011-02-01T16:02:45.999-08:00JavaLite HTTP gets Basic HTTP AuthenticationWhile I'm not a big proponent of Basic HTTP Authentication, some people find it useful. Usually when you use internal services, you do not need any authentication - you use firewalls and other restrictions. <br />
<p>When we expose services to partners, we usually define some sort of token based authentication that is application - specific. However, the JavaLite HTTP package being general purpose HTTP client needed Basic Auth.<br />
<br />
<p>The new method I added is <code>basic(user, password)</code>, here is a sample of code using basic authentication:<pre class="brush: java;">Get get = Http.get("http://localhost:8080/manager/html").basic("tomcat", "tomcat");
System.out.println(get.text());
System.out.println(get.headers());
System.out.println(get.responseCode());
</pre><br />
I used Tomcat 6 to test against, and it worked just fine after simple Tomcat configuration:<br />
<br />
<pre class="brush: xml;"><tomcat-users>
<role rolename="tomcat"/>
<role rolename="role1"/>
<user username="tomcat" password="tomcat" roles="tomcat,manager"/>
<user username="both" password="tomcat" roles="tomcat,role1"/>
<user username="role1" password="tomcat" roles="role1"/>
</tomcat-users>
</pre><br />
What you see above is tomcat-users.xml file, where I uncommented all XML and added a "manager" role to "tomcat" user.<br />
<br />
As usual, I like it when: simple things are simple.<br />
<br />
Enjoy,<br />
<br />
IgorIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com1tag:blogger.com,1999:blog-7318041760132105098.post-71474185320433205812011-01-12T15:01:00.000-08:002012-04-26T18:17:14.186-07:00Java: REST with ease :)<div style="background-color: yellow;">
Update: you can get the latest Http client from Maven central:<br />
<a href="http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.javalite%22%20AND%20a%3A%22javalite-common%22">http://search.maven.org/#search|gav|1|g%3A%22org.javalite%22%20AND%20a%3A%22javalite-common%22</a></div>
<br />
Ever wanted to just send an HTTP request from Java? What should be easy is actually not. There are myriads of ways to do this in Java; you can write a half of page of ugly code with exceptions, use Apache HTTPClient library (which has its own dependencies), find another library, learn its API, etc. I told myself: "... but I just need to call a service and get a reply back!".<br />
Eventually I got tired of this situation, and wrote my own tiny library for doing this: JavaLite.<br />
<br />
Here is an example. If all you need is to send a GET request and get a response back, you could do this in one line:<br />
<pre class="brush: java;">Get get = Http.get("http://yahoo.com");
System.out.println(get.text());
System.out.println(get.headers());
System.out.println(get.responseCode());
</pre>
The implementation has no dependencies and relies solely on standard Java API. The library even sets sensible defaults for timeouts. Also supports POST, DELETE and PUT. <br />
The reason I developed it is because we are heavily relying on using <b>REST services</b> and a simple call to a service is really a must have.<br />
So, an example of a service call would look like this:<br />
<pre class="brush: java;">if(Http.post("http://host/context/resources", postContent).text().equals("OK")){
//..success
else{
//failure
}
</pre>
Eat that, SOAP! The code is so unobtrusive, sometimes it is hard to see. Oh, boy, I can breath now... head is cool, feet are warm...live is better now :)<br />
Happy coding!<br />
igorIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com29tag:blogger.com,1999:blog-7318041760132105098.post-78699010438210972422010-09-02T14:18:00.000-07:002011-01-12T15:09:41.026-08:00Changing SSH port on Ubuntu ServerI followed so many online postings that did not work for me. Apparently Ubuntu has two files for SSHD configuration: <br />
<code>/etc/ssh/ssh_config<br />
</code>and <code><br />
/etc/ssh/sshd_config<br />
</code>Both of these files have the port setting, but only the <b>second</b> one works for me.<br />
Everyone is giving advice to change the port in the first file, however it just does not work. <br />
After I changed the setting in the <br />
<code>/etc/ssh/sshd_config</code> <br />
and restarted the SSH daemon, all was fine!<br />
Do not forget to restart the daemon:<code><br />
sudo /etc/init.d/ssh restart<br />
</code><br />
Cheers,<br />
igorIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com1tag:blogger.com,1999:blog-7318041760132105098.post-39597996254209529912010-07-19T13:22:00.000-07:002010-12-29T17:55:34.489-08:00ActiveJDBC has been released on Google codeGood news for those waiting for ActiveJDBC, it has been released under Apache 2 license. The project code can be found on Google Code: <a href=" http://code.google.com/p/activejdbc/"> http://code.google.com/p/activejdbc/</a>. <br />
Going forward, I will be blogging about this project on a <a href="http://java.productiveedge.com/">ProductiveEdge Java Blog</a>.<br />
<br />
Thank you for patience, enjoy!<br />
<br />
igorIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com2tag:blogger.com,1999:blog-7318041760132105098.post-57145292799308758412010-04-22T23:33:00.000-07:002010-05-10T23:32:01.538-07:00ActiveJDBC the BasicsThe title of this post has a class name in it...almost. The real class name is <code>activejdbc.Base</code><br />
<br />
This is an interesting class, in a sense that it is a completely static class (all methods static) and it is designed to wrap standard JDBC functionality in the most simple and succinct way humanly possible.<br />
It allows to open a connection, query DB and close a connection in 3 lines of code - you have to write a half of page for this in any Java technology!<br />
Here are some examples:<br />
<pre class="brush: java;">Base.open("oracle.jdbc.driver.OracleDriver", "jdbc:oracle:thin:@localhost:1521:xe", "usr", "pwd1");
List<Map> records = Base.findAll("select * from people");
//..iterate over list
Base.close();
</pre>As you can see, this exposes all SQL that is interesting to a developer and hides all the ungodliness of JDBC, including driver, connection, exceptions, etc. <br />
I literally bent backwards (well almost:)) to make this code as clear as possible. <br />
In the example above, the Base.open() opens a connection and attaches it to a thread. This allows any subsequent call consume it, while Base.close() closes the connection, obviously.<br />
Another example:<br />
<pre class="brush: java;">List<Map> records = Base.findAll("select * from people where last_name = ? and name = ?", "Smith", "John");
</pre>I think this one is self-explanatory...and another one:<br />
<pre class="brush: java;">Base.find("select * from people", new RowListenerAdapter() {
public void onNext(Map record) {
System.out.println(record);
}
});
</pre>In the former examples, the entire result set (findAll()) was read into a list, but in some cases you will need to read millions of records and process them as in the stream (SAX - style of sorts).<br />
The latter example achieves this goal, and you do not have to write a loop, the Base class takes care of it. <br />
<br />
The Base class is not a super class to anything. It is just a utility that can be used externally and of course is used internally by the framework. <br />
<br />
cheers,<br />
igorIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com8tag:blogger.com,1999:blog-7318041760132105098.post-19318217609362723182010-03-16T21:53:00.000-07:002010-08-12T18:01:15.327-07:00ActiveJDBC Features - Birds View<div style="background-color: yellow;">August 12 update: it seems that some people link directly to this post and do not see in later posts that this project has been published on Google Code: <b> <a href="http://code.google.com/p/activejdbc/">http://code.google.com/p/activejdbc/</a></b></div><span style="background-color: yellow;">Original post text follows:</span><br />
<p><br />
This blog is not really a tutorial, but rather a high level overview of some important features this framework has. As I stated in a previous post, I really bent backwards when implementing it, only to make it easier for developers to access persistent data.<br />
<br />
I will present various use cases in a list format:<br />
<br />
<h4>How to run a simple query<br />
</h4><pre class="brush: java;">//find by id:
Person p = Person.findById(0);
//find first:
Person p = Person.first("name = ?", "John");
//simple select of multiples:
List<Person> people =
Person.where("department = ? and hire_date > ? ", "IT", hireDate);
//...iterate
</pre><h4>How to build pageable resultsets<br />
</h4><pre class="brush: java;">List<Employee> people =
Employee.where("department = ? and hire_date > ? ", "IT", hireDate)
.offset(21)
.limit(10)
.orderBy("hire_date asc");
...iterate
</pre><br />
This query will ensure that the returned result set will start at the 21st record and will return only 10 records, according to the "orderBy". The ActiveJDBC has a built in facility for various database flavors and it will generate appropriate SQL statement that is specific for a DB (Oracle, MySQL, etc) and is efficient. It will not fetch all records, starting with 1. <br />
I tried these queries on tables with millions of records on Oracle and performance is flat. <br />
In fact, you can learn how to create queries like this if ActiveJDBC logging is enabled.<br />
<h4>How to create new records<br />
</h4><pre class="brush: java;">Person p = new Person();
p.set("name", "Marilyn");
p.set("last_name", "Monroe");
p.set("dob", "1935-12-06");
p.saveIt();
</pre><br />
This code should be self explanatory. As you can see, ActiveJDBC does not require to have getters and setters. You can write them, if you like, but IMHO, they are nothing but code pollution.<br />
<br />
The <code>set(name, value)</code> method returns reference to the same model object, which makes it possible to string method calls like this:<br />
<br />
<pre class="brush: java;">Person p = new Person();
p.set("name", "Marilyn").set("last_name", "Monroe").set("dob", "1935-12-06").saveIt();
</pre><br />
There is even a third way to set values into a model:<br />
<br />
<pre class="brush: java;">String[] names = {"first_name", "last_name", "dob"};
Object[] values = {"John", "Doe", new Date(johnsDobTime)}
Person john = new Person();
john.set(names, values).saveIt();
</pre>...and yet another way to set values into a model is with a use of a map:<br />
<pre class="brush: java;">Map values = ... initialize map
Person p = new Person();
p.fromMap(values);
p.saveIt();
</pre><br />
I hope this was entertaining. I will write more about features of ActiveJDBC in future posts. Specifically how it handles relationships. <br />
<br />
Constructive feedback is much appreciated!<br />
<br />
Have fun :)Igor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com8tag:blogger.com,1999:blog-7318041760132105098.post-69672582148640598852010-02-01T22:54:00.000-08:002010-05-10T23:20:22.215-07:00ActiveRecord in Java == ActiveJDBCAs a Java developer, I spent a a couple of years working in a mixed environment where Java and Ruby intermixed. Working side by side with Ruby developers made me aware of things outside the Java world. To some extend, this was my own fault for ignoring the Ruby world. I clearly remember beng at the SD West conference in 2005 when the Ruby frenzy began. I looked at what RoR can do and was unimpressed by it mostly because the presentations at the conference focused on generating an application from scratch using scaffolding. Having to implement web app generators for Hibernate/Tiles/Struts-Layout two years prior, this looked boring and I put my interest to Ruby on the back burner. I was wrong. A couple of years later, working in a mixed environment (Java/Ruby) I learned a whole a lot more about Ruby and Rails, and was pleasantly surprised by the level of innovation. Over the years I have developed somewhat a disgust for big frameworks and "architectures" using them. The biggest offender IMHO is Spring. I really, really, REALLY do not understand what value it provides. The Spring context files multiply like rabbits, making it extremely difficult to debug the application. As you can imagine, in a mixed environment, there were many heated discussions on the merits of different languages, and I tended to protect Java, stating that the Java environment was poisoned by large useless frameworks as well as a large number of corporate developer-drones, and really there is nothing wrong with the language. The argument that the Ruby folks had was that Ruby is more elegant, dynamic and powerful and therefore attracts a more sophisticated crowd. My arguments that there are plenty examples of outstanding software created in whatever language (including Java) were just brushed aside. On the flip side, when Ruby becomes as successful and as prominent as Java, it too will be flooded by corporate bonehead developers. I think that some of the Ruby folks behave as Ruby were a cult, not another tool at developers' disposal. So, to make the story short, the desire to prove that it is totally possible to create a lightweight persistence layer in Java similar to ActiveRecord, and make it even simpler to use in some regard, as well as desire to roll up my sleeves and just do some coding (I have done too much architecture and management over the past few years), drove me to create another ORM framework in Java, named ActiveJDBC.<br />
The idea is to model the behavior and feel similar that of ActiveRecord, but make it for the Java developer. It is amazing how little Java developers know of Ruby. RoR has some great features, and despite the fact that there is no method_missing in Java, many ideas are possible to borrow and implement in Java.<br />
The ActiveJDBC is already used on one commercial project, and according to developers who are used to Hibernate, they "do not even notice it, it just works".<br />
My design goals were:<br />
<ul><li>Should infer all metadata from DB (like ActiveRecord)</li>
<li>Should be very easy to work with</li>
<li>Should reduce amount of code to a minimum</li>
<li>No configuration, just conventions</li>
<li>Some conventions are overridable in code by simply calling methods (this will be aided by IDEs)</li>
<li>No need to learn another language</li>
<li>No need to learn another QL - SQL is sufficient</li>
<li>Code must be lightweight and intuitive, should read like English</li>
<li>No sessions, no "attaching, re-attaching" </li>
<li>No persistence managers. </li>
<li>No classes outside your own models.</li>
<li>Models are lightweight, no transient fields</li>
<li>No proxying. What you write is what you get (WYWIWYG :))</li>
<li>Should have the least possible resistance to startup a project</li>
<li>No useless getters and setters (they just pollute code). You can still write them if you like.</li>
<li>No DAOs and DTOs - this mostly junk code anyway</li>
</ul>Well, enough suspense, I can say that I started development on my free time around September, and at the end of October I had something I could use in a real system.<br />
Let's look at code examples. <br />
Here is an example of a model:<br />
<br />
<pre class="brush: java;">public class Person extends Model {}
</pre><br />
Despite the fact that there is no code in it, it is fully functional and will map to a table called PEOPLE automatically. Here is how to use it:<br />
<br />
<pre class="brush: java;">List<Person> people = Person.find("name = 'John'");
Person aJohn = people.get(0);
String johnsLastName = aJohn.get("last_name");
</pre><br />
As you can see, the amount of code is reduced to a level when it is actually readable.<br />
Finder methods can also be parametrized like this:<br />
<br />
<pre class="brush: java;">List<Person> teenagers = Person.find("age > ? and age < ?", 10, 20);
</pre><br />
ActiveJDBC supports many features and is great for building web applications as well. It has a nice validation mechanism similar that of ActiveRecord, automatic support of many to one and many to many relationships, batch deletes and updates (conditional too), etc. Too many to list. I hope this wets your appetite. Any feedback and suggestions are welcome.<br />
<br />
cheers!Igor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com15tag:blogger.com,1999:blog-7318041760132105098.post-86302940979410565632009-10-28T12:55:00.000-07:002009-11-21T23:11:43.267-08:00Daily VIM commandsThese are commands I found to be using frequently when on command line:<br />
<br />
<span style="font-weight: bold;">Window Operations:</span><br />
<ul><li>:split - horizontal split</li>
<li>:vs - vertical split</li>
<li>:vsplit - vertical split</li>
<li>Ctrl + W, Ctrl + W - will tab between windows</li>
<li>Ctrl + W, _ - will maximize current window</li>
<li>Ctrl + W, = - will resize all windows equally</li>
<li>4 CTRL-W + - will increase height of window by 4 lines</li>
</ul><span style="font-weight: bold;">File Explorer:</span><br />
<ul><li>:e <tab> - will tab through the files available in current directory</tab></li>
<li>:cd <..> - will change to directory, just like system command</li>
<li>:Ex - open file explorer in current window</li>
<li>:Sex - split current window and open explorer in one of windows</li>
<li>Hit a file to open that file in current window</li>
<li style="font-family: lucida grande;">Ctrl + 6 to go back to explorer from opened file</li>
</ul><span style="font-weight: bold;">Search/Replace </span><br />
<ul><li>:s/OLD/NEW - find and replace a first occurrence on current line</li>
<li>:s/OLD/NEW/g - find and replace all occurrences on current line</li>
<li><span style="font-size: 100%;">:%s/OLD/NEW/g</span> - find and replace all occurrences in entire file<br />
</li>
</ul><span style="font-weight: bold;">Diffing files</span><br />
<ul><li>From within VI: :vertical diffsplit file</li>
<li>From command shell: vimdiff file1, file2</li>
</ul><span style="font-weight: bold;">Buffer Operations</span><br />
<ul><li>:ls - will list currently open buffers</li>
<li>:bn - will open a buffer n, where n is a number as reported by ls</li>
<li>:b <tab> - tab through open buffers, select one to open with Enter</tab></li>
</ul><span style="font-weight: bold;">Tabs</span><br />
<ul><li>:tabe - opens a new tab (tab in edit mode)</li>
<li>gt - advance to the next </li>
<li>gT - advance to the previous </li>
<li>{count}gt - go to the {count} tab</li>
<li>:tabe - path/to/file - to open a file</li>
<li>:tabn - go to next tab</li>
</ul><span style="font-weight: bold;">External Commands</span><br />
<ul><li>:pwd - print working directory</li>
<li>:cd - as usual - move to directory</li>
<li>:cd D<tab> - will iterate through directories starting with D</tab></li>
</ul><br />
<span style="font-weight: bold;">Visual Selection Mode</span><br />
<ul><li>v - to put in the visual selection mode</li>
<li>y - yank/copy</li>
<li>x - cut selection</li>
<li>p - paste at cursoe location</li>
</ul><br />
<br />
<span style="font-weight: bold;">Autosuggest</span><br />
Ctrl + N or Ctrl + P - this will show choices when typing partial working<br />
<br />
<br />
<span style="font-weight: bold;">Expand tabs with spaces(put these onto the .vimrc file): </span><br />
:set tabstop=4<br />
:set expandtab<br />
:%retab<br />
<br />
<span style="font-weight: bold;">Mouse Support (in the .vimrc file)</span><br />
:set mouse=a<br />
<br />
<br />
This is mostly a cheet sheet for myself, ..but enjoy<br />
igorIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com0tag:blogger.com,1999:blog-7318041760132105098.post-36679716633833956372009-10-18T15:21:00.000-07:002009-10-18T16:44:30.805-07:00Ubuntu 9.04 on MacBook Pro 5.4A few days ago I purchased a new shiny MacBook Pro, and decided to install Ubuntu on it. Why? because Linux is my habitat, and also because some software packages I use are readily available on Linux, but not on Mac OS. In any case, this blog is not about Mac OS vs Linux (more on this maybe one day; I can write a book on how Mac OS sucks :)), but rather some steps I had to overcome to complete the installation.<br /><br />Out of the box, Jaunty works on MBP, with some exceptions. The trackpad is too slow be useful, the Fn key in in the reverse.<br />After installation using the Boot Camp, I followed the instructions on the Ubuntu forums: <a href="https://help.ubuntu.com/community/MacBookPro5-1_5-2/Jaunty">https://help.ubuntu.com/community/MacBookPro5-1_5-2/Jaunty</a>, additionally used information here: <a href="https://help.ubuntu.com/community/AppleKeyboard">https://help.ubuntu.com/community/AppleKeyboard</a><br />to adjust keyboard settings. All was fine, except the Trackpad refused to be configured. This has proven to be the biggest hurdle I spent the most time on... until I discovered this posting:<br /><a href="http://www.bhagwad.com/blog/2009/technology/configure-alps-synaptics-touchpad-in-ubuntu-904-jaunty-jackalope.html">Configure ALPS (Synaptics) touchpad in Ubuntu 9.0.4 (Jaunty Jackalope)</a><br />Apparently, the fdi file must be mapped to the correct HAL device (kinda makes sense :)).<br />Using this command:<br /><div style=""><br /><span style="font-family: courier new;">$lshal</span> > hal.txt<br /><br /></div>, I was able to see that the name of my device was: "<span style="font-family:courier new;">Apple Inc. Apple Internal Keyboard / Trackpad</span>".<br />Armed with this knowledge, I edited my FDI file to my liking, and HAL was able to load it, and apply my settings to the right device.<br />The trick is to find the parameter: "info.product" in the lshal output and use it in the fdi file.<br />Here is my complete fdi file after adjusting speed and sensitivity:<br /><br /><a href="http://igorpolevoy.com/public/attach/Ubuntu9.04OnMacBookPro/x11-synaptics-bcm5974.fdi">http://igorpolevoy.com/public/attach/Ubuntu9.04OnMacBookPro/x11-synaptics-bcm5974.fdi</a><br /><br />cheers,<br />igorIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com1tag:blogger.com,1999:blog-7318041760132105098.post-59347018135105859342009-01-02T13:20:00.000-08:002009-01-02T16:48:00.961-08:00Bending Outlook towards GMailI use e-mail extensively, and usually for the most part working for clients whose infrastructures are based on MS Exchange. I have tried really hard to wean myself from Outlook, but unfortunately the alternatives bring about a host of other problems (tried Thunderbird and Evolution).<br /><br />The two things I really like about GMail are:<br />* Nothing is deleted<br />* All is searchable<br /><br />One really annoying problem is that the server administrator usually sets up cleaning of the "Deleted Items" folder and you loose all those "deleted" messages for future searches. I've been using GMail for personal use since 2004, and really like the idea that nothing needs to be deleted. Configuring Outlook 2003 to save all messages has proven to be a challenge. Here is how I did this.<br /><br />First, I created a new folder under "Inbox" called "MyDeletedItems". I then wrote a VBA macro to move all messages from "Deleted Items" as well as all selected messages from any current view to "MyDeletedItems" folder.<br />Here is a code for the marco:<br /><br /><br /><div id='code' style="width:400px; background-color:beige; background-color:beige;font-family:monospace; overflow-x:scroll; white-space:nowrap"><br /><br />Sub MoveToMyDeletedFolder()<br /><br />Dim x As Integer<br />Set myDeletedItemsFolder = Application.GetNamespace("MAPI").GetDefaultFolder(6).Folders("MyDeletedItems")<br /><br />'This will move all selected messages from current view to "MyDeletedItems" folder.<br />Set sectedItems = Outlook.Application.ActiveExplorer.Selection<br />For x = 1 To sectedItems.Count<br /> 'MsgBox sectedItems.Item(x).SenderName & ":" & sectedItems.Item(x).Subject<br /> sectedItems.Item(x).Move myDeletedItemsFolder<br />Next x<br /><br />' this will move all items from standard DeletedItems folder to MyDeletedFolder<br />Set deletedItemsFolder = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderDeletedItems)<br />Set delItems = deletedItemsFolder.Items<br />For x = 1 To delItems.Count<br /> 'MsgBox delItems.Item(x).SenderName & ":" & delItems.Item(x).Subject<br /> delItems.Item(x).Move myDeletedItemsFolder<br />Next x<br /><br />End Sub<br /><br /><br /></div><br />The next step was to create a button and wire it to the macro, which was fairly easy. The really awkward way of adding a shortcut to buttons in Outlook shocked me. This is done by changing a text associated with a button. You need to pre-pend the name with a '&' character, which will make pressing Alt+'next character' possible. For instance, if the label on the button is "&Delete Message", then this button is associated with a Alt+D keyboard shortcut. Editing the button text is equally unfriendly. Thanks to all the people whose links I cannot reproduce here (i googled extensively to get all this information), I learned that in order to edit a button text, you have to do: Tools-> Customize, then, when the Customize dialog is up, right - click on the button to edit it's text.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wPfxa7DoRV0/SV6MGwxXuDI/AAAAAAAAAck/ECGrS9GxHF8/s1600-h/outlook-button.PNG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 250px;" src="http://3.bp.blogspot.com/_wPfxa7DoRV0/SV6MGwxXuDI/AAAAAAAAAck/ECGrS9GxHF8/s320/outlook-button.PNG" alt="" id="BLOGGER_PHOTO_ID_5286817060378622002" border="0" /></a><br /><br />As you can see from screenshot, my configuration is 'Alt+X'.<br /><br />Since there is much written about Outlook security on the web, I will not repeat it here, but getting to run the macros is not straight forward. Instead of changing the security levels, I chose to create s self - signed certificate and us it for the macros.<br />Here are the steps to dot this:<br /><ul><li>Generate a self-signed certificate. This can be done with a variety of tools, but the simplest way to do this is to use MS - provided SelfCert.exe. On my machine, it is located here: <code>c:/Program Files/Microsoft Office/Office11</code></li><li>In VBA Editor, do: Tools-> Digital Signature -> Choose .. and choose a certificate you just generated.</li></ul>After this step, I was able to run the macro by just selecting a message in my inbox and pressing 'Alt+X'.<br />I think that when I started poking around all these steps, Outlook prompted me if I want to enable macros for X number of days, I selected some value and completely forgot it. Sure enough, after a dye days :) this stopped working and Outlook presented me with a message saying that I need to "Enable macros" from the application (Outlook). This was very annoying, and I had to dig further.<br />After some poking around, I figured that the certificate I created is a type of a "personal certificate", which can be seen in Internet Explorer Tools-> internet Options-> Content -> Certificates -> Personal. I exported this certificate and imported it back in as "Trusted Root Certificate", which solved this problem. I can run my macros again (till further obstacle from MS :)).<br /><br />Once you import the certificate as "trusted Root Certificate", start Outlook again and try to run the macro, you will be presented with this dialog:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_wPfxa7DoRV0/SV61fGvJmTI/AAAAAAAAAcs/5F76lqTShPc/s1600-h/enable-macros1.PNG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 193px;" src="http://2.bp.blogspot.com/_wPfxa7DoRV0/SV61fGvJmTI/AAAAAAAAAcs/5F76lqTShPc/s320/enable-macros1.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5286862558568487218" /></a><br />At this point, mark "Always trust macros from this publisher" and press "Enable Macros" button.<br /><br /><br />The last thing to make Outlook to behave close to GMail is to have a good search. While I generally believe that the Google Desktop is a search engine superior search to Windows search, I have a few gripes about it. First, when an e-mail message is found, there is no way to see what folder a message belongs to. Additionally, there is a pretty annoying bug in Google Desktop and Outlook integration, which sometimes prevents a link "Open in Outlook" to work. This makes it impossible to reply to and forward messages found through a search engine. Windows search, on the other hand has a tight integration with Outlook (surprise !), and is working well albeit slower than Google.<br /><br />I have an e-mail environment for corporate e-mail that is somewhat close to GMail - nothing is deleted, and all is searchable.<br /><br />I hope this help someone.Igor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com1tag:blogger.com,1999:blog-7318041760132105098.post-55920562425541227152008-09-27T21:23:00.000-07:002008-09-28T00:46:16.553-07:00As a Java developer I'm sometimes bitten by a bug when runtime loads a wrong class form a wrong library. Often times I'd loose a lot of time tracing the problem to multiple versions of the same library loaded. This quite often happens when you use Maven. For instance, if you put a dependency on two different libraries, and one of them pulls down one version of Log4J, while another loads a different version of it, you are going to end up with two versions of the same. Chances are that they not compatible with one another.<br /><br />After stumbling into this situation a few times, I decided to write a simple Swing based app for tracing down all the jars in a specific directory. Thus, the JarExplorer was born.<br /><br />JarExplorer is a simple tool which can be used to inspect large jar repositories. It will allow to locate classes, property files, images, and all other resources inside those libs.<br /><br />It works very well for me, and I hope someone else will also find it useful.<br /><br />It can be downloaded from the following location:<a href="http://code.google.com/p/jar-explorer/"> http://code.google.com/p/jar-explorer/</a><br /><br /><br />Besides ability to open images, text and HTML, it also alloes to peek inside classes. It will show inheritance, all methods (even private) as well as all member variables. This is accomplished via use of a library called javad: <a href="http://www.bearcave.com/software/java/javad/index.html">http://www.bearcave.com/software/java/javad/index.html</a> by Ian Kaplan.<br />Java reflection was too limiting for the purpose, but Ian's library worked quite well.<br /><br />The JarExplorer is fully self-sufficient, and does not require anything else (besides Java :)).<br />When it starts up, point it to a directory with jar files and wait a bit until it indexes every jar in it (recursively of course). After that you can do very fast searches using this tool.<br /><br /><br />Good luck<br />igorIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com0tag:blogger.com,1999:blog-7318041760132105098.post-45847400765800081422008-02-18T16:31:00.000-08:002008-09-27T22:35:03.621-07:00Exadel Flamingo ReleasedAlthough this blog is a bit late on the news, nonetheless, we finally released Exadel Flamingo 1.6. This is a bog milestone for the project.<br />For those who does not know what Flamingo is, can refer to the following articles: <a href="http://www.adobe.com/devnet/flex/articles/flex_seam.html">Integrating Flex with Seam and Flamingo.</a><br />Even though this article describes integration with JBoss Seam, Flamingo supports combination of Spring/Hibernate <span style="font-style: italic;">pretty much the same</span>.<br /><br />The new release, besides the previous features, contains vast improvements. It moved made a few steps in the direction to become an agile development framework for Flex on Java. The features of interest are:<br /><ul><li>Code generation greatly improved with generation of ActionScript files from Java, added ability to create CRUD screens for entities with relations (e.g. one-to-many)</li><li>'CallSet' and 'Binding' Flex components added for Spring</li><li>Added "search by relationship" and sorting for dynamic methods</li><li>Spring Security integration added</li></ul><br />The nice thing about Flamingo is now, you can develop applications on Flex blazingly fast. There is a wealth of simple scripts to generate most artifacts in the project, including a fully working scaffolding for entities - completely wired up. This is a great way to prototype a relationship model.<br /><br />Another advanced feature is Dynamic Persistent Methods. This allows Flex developers to simply call methods on the remote object <span style="font-style: italic;">even though these methods are not declared anywhere!<br /></span>Here is an example:<br />Let's say you have a Hibernate entity class declared like this:<br /><pre><br />@Entity<br />public class Person implements Serializable {<br /> private String name;<br /> public String getName() {<br /> return name;<br /> }<br /> public void setName(String name) {<br /> this.name = name;<br /> } <br />} <br /></pre><br /><br />On the client side, you can just execute this:<br /><pre><br /><mx:RemoteObject id="person" destination="Person" result="resultHandler(event)"/><br />...<br />private function resultHandler(event:ResultEvent):void<br />{<br /> entities = event.result as ArrayCollection;<br />}<br />...<br />person.findAll();<br />person.findByNameLike("John%");<br />person.findByNameNotEqual("John Smith");<br /></pre><br /><br /><br />The simplicity and power are apparent. No need for extra configuration, no need to think about mapping of web services, the call just executes and returns what is expected.<br /><br />Dynamic Persistent Methods also support relationships. If you have two entities in a relationship:<br /><br /><pre><br />@Entity<br />public class Author implements Serializable {<br /><br />private Set<Book> books;<br />@OneToMany(mappedBy = "author", fetch = FetchType.EAGER)<br /> public Set<Book> getBooks() {<br /> return books;<br /> }<br />}<br />@Entity<br />public class Book implements Serializable {<br /> private Author author;<br /> <br /> @ManyToOne(fetch = FetchType.EAGER)<br /> public Person getAuthor() {<br /> return person;<br /> }<br />}<br /></pre><br /><br />On the Flex side, you can call dynamic methods on relationships like this:<br /><br /><code><br /><mx:RemoteObject id="book" destination="Book"/><br />...<br />book.findByPerson(currentPerson)<br /></code><br /><br />How was this accomplished, since these methods were not declared on the class "Person" in Java? There is not magic here, just some clever programming. Flamingo on the server side parses the request from the call, and recognizes that a method is dynamic. Then, based on the syntax rules for method names, it generates a dynamic Hibernate SQL query, executes it and returns results back to the caller (on the client side!).<br /><br />As you can see, this is some powerful stuff. Of course, Flamingo is not for everyone. If you develop business database driven applications, Flamingo is a perfect candidate for consideration, if you already have an application based on Seam or Spring/Hibernate and you want you make it mode dynamic, Flamingo will suit well.<br /><br />Exadel Flamingo lives here: <a href="http://www.exadel.com/web/portal/flamingo">http://www.exadel.com/web/portal/flamingo</a><br /><br />Good luckIgor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com4tag:blogger.com,1999:blog-7318041760132105098.post-48519128736632418782007-04-08T01:45:00.000-07:002008-02-18T16:30:03.769-08:00Offshoring Pitfalls in the TrenchesIf you are like me (corporate architect/software dev. manager working for a large company), then you probably could not avoid to be sucked into the "outsourcing black hole". Let me share my experiences on the subject.<br /><br />In general, the higher level management of a corporation gets this "we need to be as efficient as X" bug, and then goes on to setup corporate policies for engagement with outsourcing partners. Normally (at least in my experience), the decisions come down to people like me to work with a team of developers in another country. This team would be pre-selected by management of the vendor itself, and often times, the qualifications of the offshore team members might not exactly match your projects needs. In addition to that, there could be a whole host of other impediments that you do not normally have when working with a local group:<br /><ul><li>Pre-selected team</li><li>Cultural barriers</li><li>Language barriers (not the same as cultural)</li><li>Time difference</li><li>Lack of good communications (IM, screen sharing, phone, VPN, Wiki, etc.)</li><li>Lack of a development ecosystem (VCS, bug tracking system, continuous build, integration env.)</li><li>Wrong contracting agreement (time boxing)</li></ul>My first account with outsourcing was around 2003, when I was asked to deliver an internal project, and was given a team of four developers and an on-shore liaison from an approved vendor in India. I bravely charged ahead without thinking too much that the project actually was not setup right. This first project went exactly according to the Murphy's Law: "If anything can go wrong, it will..". The bullet list above is not a coincidence, as it came directly from my experience on this project. Every aspect of this project has gone wrong. To begin with, I probably should provide a technology overview of the project. The task was to build an internal database of UML models. This was a web-based J2EE application, which stored UML models in a native XML database. The architecture was not that complicated, but there was a lot of work with new technologies (native XML database, XPath, XQuery, EJBs, generated JavaScript, etc.).<br /><br />Let's start describing every problem we faced. First off, we were assigned a pre-selected team for this project. Well, this is a strange world. When we hire full time employees, or even consultants to do the job, we go far and above in the interviewing process to ensure that the candidate is indeed qualified to do the job. On the other hand, when we work off-shoring vendors, somehow we are handed down teams that were put together without any input from the actual architecture and management of the project - just because they were provided by an "approved vendor". This, of course allows vendors abuse the situation and allocate junior team members to projects in order to cross-train them. When the project started, and I was able to interview some of the developers in the off-shore team, I was shocked to find out that they were all in their early twenties (nothing wrong with that, as long as there is experience) and only one team member had a cursory knowledge of UML(heard of it). None of the developers possessed any of the knowledge of technologies necessary to complete this project. In other words, there was a great mismatch between the experience of the team members and the project demands, so we started with the introduction to UML :).<br /><br />Second, I quickly realized that there were cultural differences between our working style and that of the off-shore team. It came in a form of full agreements during the design and architecture discussions. When we started to receive deliverables, we realized that they had no resemblance to what was discussed and "agreed" upon.<br /><br /><br />Time difference. The time difference between Chicago and Bangalore (location of the off-shore team) is 11 hours, which pretty much prevents any live communications within the normal work ours. This translated into a lot of extra hours spent by US team members as well as the vendors'.<br /><br />Lack of good communications. This is an area where our own management (either due to lack of understanding, or lack of attention) failed miserably. Software development is a highly social process, and requires people to be in constant communications. The only communication channels we had on this project were phone and e-mail. The following communication channels are a must for every project and especially<br />for an off-shoring one: instant messaging, screen sharing, phone, VPN, Wiki. Unfortunately, we had none of these, except for mail and phone. This resulted in extremely inefficient communications often delayed by days, with screen shots included. A simple e-mail "question - answer - confirmation" could take up to four days (did management factor this into the bottom line of off-shoring? ). We did not get IM, VPN, and shared Wiki because of our own managements' security concerns (which were superficial of course, as all code was sent back and fourth by e-mail!).<br /><br />The off shore team used their local VSS as a source control system, while we used CVS. Each morning we would have an e-mail code dump, and quite often we had a very difficult time checking it in, merging, compiling, and running. Sometimes this activity alone would devour a good half a day.<br /><br />The last but not the least, the contract agreement. I'm a firm believer that an agreement with any vendor must be based on a actual deliverables, and never just time - boxed, as it was on this project. The entire project was scheduled for nine months, but the off-shore contract (for reasons unknown to me) was only for fife. This meant that the off-shore team was not in any position to be responsible for just about anything they delivered. They would not be on the project long enough to see it go live.<br /><br />All of the above resulted in the fact that about of 90% of code delivered by the off-shore team was discarded soon after the off-shore team rolled of the project, and the system was completed by a local team via a heroic effort. Of course, the management deemed it a successful use of the off-shore resources - how ironic!<br /><br />Hey, you have been patient enough to read up until this point – my hat is off to you :). You might ask what is the moral of this story? The bottom line is that modern software development is a very hard process, and it should be approached very seriously. Working with off-shore vendors makes it much more difficult and sometimes creates problems you might not even think of when working with a local team. In addition to that, off-shoring work creates so many inefficiencies, which need to be factored in when deciding whether it is going to be good for your organization.<br />In other words, before an organization embarks on an off-shoring initiative, it needs to get it's ducks in a row, by providing a more productive environment, all possible better communication channels, better structured contracting agreement, etc - I think you get the point.<br /><br />So, is the outlook so bleak? Not really, if it is approached properly. I will tell the success story in the next posting.<br />Any thoughts?Igor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com0tag:blogger.com,1999:blog-7318041760132105098.post-49132818084297707982007-04-07T20:59:00.000-07:002007-04-07T21:43:02.612-07:00Good Day to Start a BlogWell, finally a day has come for me too to get on a band wagon of blogging. Why blog, why me , why now? It is that as a Java professional working an living many of the ups and downs of the IT industry during the course of my professional career, I have many thoughts that I discuss with my fellow co-workers and other people in the industry that think alike. This blog is to continue the same, but for a wider audience. General topics that will be discussed here range from , to somewhat vague topics such as:<br /><ul><li>Very technical HOW TOs</li><li>Various architectural approaches - pros/cons<br /></li><li>Efficiency of a development process</li><li>How to create a winning team<br /></li><li>What does it mean to create architecture</li><li>Future directions of IT in the world of constantly changing technologies</li><li>How to survive in constantly globalized economy</li><li>anything else that comes to mind and has any relevancy to the topics above</li></ul>The real reason that I'm starting this Blog, is that I'd like to discuss these topics, potentially get comments from other people who ask themselves the same questions, and generally exchange ideas.<br /><br />You might ask: "Why another blog on the same? Isn't it enough out there that is printed in magazines, published on the Internet, etc". Well, maybe, but a lot this kind of information is scattered out there and sometimes too formal (especially the enterprise architecture stuff). What I want to discuss here are simple practical approaches for getting things done.<br /><br />A couple of words about me. I came into the world of software from electrical engineering. Actually I enjoyed this profession, but somehow (unbeknownst to myself), gradually moved into the world of software in the early 90s. I started to work in Java when the JDK could fit on the floppy disk, and have gone through many phases in my professional career, from consulting to Enterprise Architecture, to software development management, back to architecture consulting. I have also been teaching various Java related topics at the<a href="http://ipdweb.cs.depaul.edu/"> DePaul IPD</a> for the last eight - nine years.<br /><br />So, please do not hesitate to comment on any of my postings.<br /><br />Have fun :)Igor Polevoyhttp://www.blogger.com/profile/03725729050038133735noreply@blogger.com2