Ruby on Rails für Java Entwickler - Ende der Schmerzen - first, last = :mariano, :kamp email = #{first.#{last@de.ibm.com
Ruby on Rails für Java Entwickler - Ende der Schmerzen - first, last = :mariano, :kamp email = #{first.#{last@de.ibm.com
Es war einmal
Vor langer Zeit
1993
In einem fernen Land
Ein Ritter in schimmernder Rüstung
Yukihiro Matsumoto
Yukihiro Matsumoto Matz
Suche nach dem Edelstein
Ruby!
Smalltalk Perl + ~= Ruby http://flickr.com/photos/letioux/110269051/
Smalltalk Perl objektorientierung + dynamik ~= Ruby http://flickr.com/photos/letioux/110269051/
Smalltalk Perl objektorientierung dynamik + reguläre ausdrücke string manipulationen ~= Ruby http://flickr.com/photos/letioux/110269051/
was ist ruby?
programmiersprache
for first
for human beings first
then computers Matz
objektorientiert
objektorientierung kapselung vererbung polymorphie
objektorientierung
objektorientierung everything is an object
objektorientierung ja, ja...
objektorientierung nein, diesmal wirklich!
objektorientierung >> "ruby".class => String
objektorientierung >> "ruby".class IRB-In => String
objektorientierung >> "ruby".class => String IRB-Out
objektorientierung >> 10.class => Fixnum
objektorientierung >> 10.class => Fixnum Java Primitives sind keine Objekte!
objektorientierung >> nil.class => NilClass
objektorientierung >> nil.class => NilClass Java Schlüsselwort null
objektorientierung >> true.class => TrueClass
objektorientierung >> true.class => TrueClass Java Schlüsselwort true
objektorientierung objekte senden und empfangen nachrichten
objektorientierung >> 10.div(2) => 5
objektorientierung >> 10.div(2) => 5 Java Nicht für Primitives
objektorientierung >> 10.send(:div, 2) => 5
objektorientierung >> 10./2 => 5
objektorientierung >> 10/2 => 5
objektorientierung >> 10/2 => 5 Java Nur für Primitives
objektorientierung >> 10.send(:/, 2) => 5
objektorientierung >> String.new "ruby" => "ruby"
objektorientierung >> String.new "ruby" => "ruby" Java Schlüsselwort new
objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil
objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil
objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil
objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil Define a setter
objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil Define a getter
objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil >> d = Dog.new => #<Dog:0x1d4bac> >> d.name="fluffy" => "Fluffy" >> d.name => "Fluffy"
objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil >> d = Dog.new => #<Dog:0x1d4bac> >> d.name="fluffy" => "Fluffy" >> d.name => "Fluffy" Dog d = new Dog()
objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil >> d = Dog.new => #<Dog:0x1d4bac> >> d.name="fluffy" => "Fluffy" >> d.name => "Fluffy" d.setname( Fluffy )
objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil >> d = Dog.new => #<Dog:0x1d4bac> >> d.name="fluffy" => "Fluffy" >> d.name => "Fluffy" d.getname()
dynamisch
dynamik
dynamik everything is open
dynamik sogar die ruby libraries
dynamik >> class Fixnum >> def even? >> self % 2 == 0 >> end >> end => nil >> 10.even? => true >> 9.even? => false
dynamik >> class Fixnum >> def even? >> self % 2 == 0 >> end >> end => nil >> 10.even? => true >> 9.even? => false Java Subclassing, wenn erlaubt Helper Klassen -> StringUtil
dynamik und bereits lebende objekte
dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end
dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end
dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end
dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end
dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end
dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end
dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end
dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end >> Player.find(:all).size => 4
dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end >> Player.find(:all).size Executing: SELECT * FROM players => 4
dynamik
dynamik weak typing
dynamik strong/static typing weak typing
dynamik strong/static typing dynamic typing weak typing
dynamik dynamic typing >> def sum(a, b) >> a+b >> end => nil
dynamik dynamic typing >> def sum(a, b) >> a+b >> end => nil >> sum(1,2) => 3
dynamik dynamic typing >> def sum(a, b) >> a+b >> end => nil >> sum("a","z") => "AZ"
dynamik dynamic typing >> def sum(a, b) >> a+b >> end => nil >> sum("a",2)
dynamik dynamic typing >> def sum(a, b) >> a+b >> end => nil >> sum("a",2) TypeError: can't convert Fixnum into String
dynamik :method_missing
dynamik >> class Receiver >> def method_missing(action, *args) >> puts "My method #{action was called," >> puts "with parameters: #{args.inspect" >> end >> end
dynamik >> class Receiver >> def method_missing(action, *args) >> puts "My method #{action was called," >> puts "with parameters: #{args.inspect" >> end >> end >> r = Receiver.new => #<Receiver:0x33d43c>
dynamik >> class Receiver >> def method_missing(action, *args) >> puts "My method #{action was called," >> puts "with parameters: #{args.inspect" >> end >> end >> r = Receiver.new => #<Receiver:0x33d43c> >> r.test My method test was called, with parameters: [] => nil
dynamik >> class Receiver >> def method_missing(action, *args) >> puts "My method #{action was called," >> puts "with parameters: #{args.inspect" >> end >> end >> r = Receiver.new => #<Receiver:0x33d43c> >> r.test My method test was called, with parameters: [] => nil >> r.add 1,"b", 2 My method add was called, with parameters: [1, "b", 2] => nil
dynamik >> class Receiver >> def method_missing(action, *args) >> puts "My method #{action was called," >> puts "with parameters: #{args.inspect" >> end >> end >> r = Receiver.new => #<Receiver:0x33d43c> >> r.test My method test was called, with parameters: [] => nil >> r.add 1,"b", 2 My method add was called, with parameters: [1, "b", 2] => nil Proxy? Mock? State Machine? CSV Reader? AOP?
dynamik meta programmierung
dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil
dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil Definiert on the fly : :name, :name=, :age, :age=
dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil Überschreibt den setter für age.
dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil >> d = Dog.new => #<Dog:0x318498>
dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil >> d.name = "Fluffy" => "Fluffy" >> d.age = 2 => 2
dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil >> d.age => 14
dynamik und vieles mehr...
blocks/closures (nur ganz kurz)
closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end
closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end
closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2
closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2
closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2
closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2
closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2
closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2 >> log("output"){puts "Chunky Bacon" Now executing Output. Chunky Bacon Done with Output. => nil
closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2 >> log("output"){puts "Chunky Bacon" Now executing Output. Chunky Bacon Done with Output. => nil >> ["chunky","bacon"].each { element puts element chunky bacon
demo!
2000
Dave Thomas
Andy Hunt
Pragmatic Programmers
Pragmatic Programmers
Pragmatic Programmers "Learn at least one new [programming] language every year. Different languages solve the same problems in different ways. By learning several different approaches, you can help broaden your thinking and avoid getting stuck in a rut."
Pickaxe
Google Trends http://www.google.com/trends?q=%22ruby+on+rails%22%2c+ejb&ctab=0&geo=all&date=all
Programming Language Trends http://radar.oreilly.com/archives/2006/08/programming_language_trends_1.html
Script Kiddies...
... Ritter...
Kent Beck
Kent Beck
Kent Beck
Kent Beck
Kent Beck I always knew one day Smalltalk would replace Java. I just didn't know it would be called Ruby.
Martin Fowler
Martin Fowler
Martin Fowler
Martin Fowler
Martin Fowler I like the ruby language for its rich yet uncluttered syntax and the well designed frameworks that come with it.
was ist nun Rails?
2004
der geistige vater
Google/O Reilly: Best Hacker
Google/O Reilly: Best Hacker
David Heinemeier Hanson (DHH)
rails ist...
mvc framwork
aus einem guss
extrahiert aus laufender anwendung
conventions configuration
conventions over configuration
opinionated software
zuckerbrot & peitsche
DRY (don t repeat yourself) drücke alles nur einmal aus
elegant
conventions
conventions Klassen- und Tabellen
conventions Klassen- und Tabellen Klassennamen sind Singular. Tabellennamen sind Plural.
conventions Klassen- und Tabellen Klassennamen sind Singular. Tabellennamen sind Plural. Klassennamen sind CamelCase. Tabellennamen sind Kleinbuchstaben, verbunden durch _.
conventions Klassen- und Tabellen Klassennamen sind Singular. Tabellennamen sind Plural. Klassennamen sind CamelCase. Tabellennamen sind Kleinbuchstaben, verbunden durch _. Bsp.: TurnState => turn_states OrderReceipt => order_receipts Person => people
conventions Spalten- und Attribute Spaltenname == Attributname Jede Tabelle hat eine id -Spalte
conventions Relationen Spaltennamen des foreign keys entspricht dem Namen der Klasse plus _id.
conventions Relationen Spaltennamen des foreign keys entspricht dem Namen der Klasse plus _id. Customer id name * Book id name author
conventions Relationen Spaltennamen des foreign keys entspricht dem Namen der Klasse plus _id. Customer id name * Book id name author Der Tabelle books wird die Spalte customer_id angefügt.
conventions... und mehr...
und? bringt s was?
JEE vs Rails http://flickr.com/photos/candiedwomanire/2238529
JEE vs Rails Java Beispielcode von Sebastian Hennebrueder http://www.laliluna.de id Customer name * Book id name author http://www.laliluna.de/ejb-3-struts-tutorial-jboss.html
/** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import java.util.set; JEE vs Rails import javax.persistence.cascadetype; import javax.persistence.entity; import javax.persistence.fetchtype; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.onetomany; import javax.persistence.sequencegenerator; import javax.persistence.table; /** * @author hennebrueder * */ @Entity @Table(name="customer") @SequenceGenerator(name="customer_sequence", sequencename="customer_id_seq") public class Customer { private Integer id; private String name; Customer id name private List books =new ArrayList(); public Customer(){ super(); public Customer(Integer id, String name){ super(); this.id=id; this.name=name; @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedby="customer", targetentity=book.class) public List getbooks() { return books; public void setbooks(list books) { this.books = books; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="customer_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String getname() { return name; public void setname(string name) { this.name = name; @Override public String tostring() { return "Customer: " + getid() + " Name " + getname();
Model -> Table @Entity @Table(name="customer") [..] public class Customer { Customer id name [..] Rails: class Customer < ActiveRecord::Base end Convention: Class Name = Customer => Table Name = Customers sonst: set_table_name( customer )
Primary Key [..] @SequenceGenerator(name="customer_sequence", sequencename="customer_id_seq") public class Customer { [..] Customer id name @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="customer_sequence") public Integer getid() { Rails: Entfällt. Convention: Primary Key => id, sequence
Relationen @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedby="customer", targetentity=book.class) public List getbooks() { return books; Customer id name public void setbooks(list books) { this.books = books; Rails: has_many :books Convention: targetentity = Singular des Entitätennames, sonst, :class_name = Book Getter/Setter dynamisch
Attributes private Integer id; private String name; private List books =new ArrayList(); public Customer(){ super(); public Customer(Integer id, String name){ super(); this.id=id; this.name=name; public Integer getid() { return id; public void setid(integer id) { this.id = id; public String getname() { return name; public void setname(string name) { this.name = name; Customer id name Rails: create_table :customers do t # keine id spalte t.column :name, :string end Convention: Name der Spalte = Name des Attributs Getter und Setter dynamisch
tostring() @Override public String tostring() { return "Customer: "+getid()+" Name "+getname(); Customer id name Rails: Entfällt, Default: #<Customer:0x2417c14 @attributes={"name"=>"donald Duck", "id"=>"1"> Alternativ: def to_s Customer: #{id Name #{name end => "Customer: 1 Name Donald Duck"
CustomerDAO, CustomerDAOImpl save/persist merge findall findbyid findbycustomer (BookDAO...) Customer id name Book id name author Rails: Alle Methoden bereits im Framework generisch enthalten findbyx dynamisch -> findbyname, findbyauthor, findbycustomer, findbytitleandauthor...
Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end
Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end
Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end
Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end
Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end
Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end
Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end
Der Code Customer id name * Book id name author class Customer < ActiveRecord::Base end has_many :books class Book < ActiveRecord::Base end belongs_to :customer
Perfection in Design This Wikipedia and Wikimedia Commons image is from the user Chris 73 and is freely available at http://commons.wikimedia.org/ wiki/image:antoine_de_saint-exup%c3%a9ry_lyon.jpg under the creative commons cc-by-sa 2.5 license.
Perfection in Design Antoine de Saint-Exupéry This Wikipedia and Wikimedia Commons image is from the user Chris 73 and is freely available at http://commons.wikimedia.org/ wiki/image:antoine_de_saint-exup%c3%a9ry_lyon.jpg under the creative commons cc-by-sa 2.5 license.
Perfection in Design You know you ve achieved perfection in design, not when you have nothing more to add, but when you have nothing more to take away. Antoine de Saint-Exupéry This Wikipedia and Wikimedia Commons image is from the user Chris 73 and is freely available at http://commons.wikimedia.org/ wiki/image:antoine_de_saint-exup%c3%a9ry_lyon.jpg under the creative commons cc-by-sa 2.5 license.
JEE vs Rails Migration Customer Book
/** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import java.util.set; import javax.persistence.cascadetype; import javax.persistence.entity; import javax.persistence.fetchtype; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.onetomany; import javax.persistence.sequencegenerator; import javax.persistence.table; /** * @author hennebrueder * */ @Entity @Table(name="customer") @SequenceGenerator(name="customer_sequence", sequencename="customer_id_seq") public class Customer { private Integer id; private String name; private List books =new ArrayList(); public Customer(){ super(); public Customer(Integer id, String name){ super(); this.id=id; this.name=name; @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedby="customer", targetentity=book.class) public List getbooks() { return books; public void setbooks(list books) { this.books = books; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="customer_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String getname() { return name; public void setname(string name) { this.name = name; @Override public String tostring() { return "Customer: " + getid() + " Name " + getname(); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.stateless; import javax.persistence.entity; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; /** * @author hennebrueder * */ @Stateless public class CustomerDaoImp implements CustomerDao { @PersistenceContext private EntityManager em; public static final String RemoteJNDIName = CustomerDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = CustomerDaoImp.class.getSimpleName() + "/local"; /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#save(de.laliluna.example.ejb.book) */ public void save(customer customer) { em.persist(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#reattach(de.laliluna.example.ejb.book) */ public void merge(customer customer) { em.merge(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findall() */ public List findall() { return em.createquery("from Customer").getResultList(); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findbyid(java.lang.integer) */ public Customer findbyid(integer id) { Customer customer = em.find(customer.class, id); return customer; /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import javax.ejb.stateful; import javax.ejb.stateless; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; import org.apache.log4j.logger; import sun.security.krb5.internal.crypto.bo; /** * @author hennebrueder * */ @Stateless public class BookDaoImp implements BookDao { @PersistenceContext private EntityManager em; private Logger log = Logger.getLogger(this.getClass()); /* * (non-javadoc) * * @see de.laliluna.example.ejb.bookdao#save(de.laliluna.example.ejb.book) */ public void save(book book) { log.debug("persist book: " + book); em.persist(book); public void merge(book book) { em.merge(book); public List findall() { log.debug("find All books"); return em.createquery("from Book").getResultList(); public static final String RemoteJNDIName = BookDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = BookDaoImp.class.getSimpleName() + "/local"; public Book findbyid(integer id) { return em.find(book.class, id); public List findbycustomer(customer customer) { log.debug("find by customer"); return em.createquery("from Book b where b.customer = :customer").setparameter("customer", customer).getresultlist(); package de.laliluna.library; import java.util.list; import javax.ejb.local; import org.jboss.annotation.ejb.localbinding; @Local public interface BookDao { public void save(book book); public void merge(book book); public List findall(); public List findbycustomer(customer customer); public Book findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.local; /** * @author hennebrueder * */ @Local public interface CustomerDao { public void save(customer customer); public void merge(customer customer); public List findall(); public Customer findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.io.serializable; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.joincolumn; import javax.persistence.manytoone; import javax.persistence.sequencegenerator; import javax.persistence.table; import org.hibernate.annotations.genericgenerator; /** * @author hennebrueder * */ @Entity @Table(name = "book") @SequenceGenerator(name = "book_sequence", sequencename = "book_id_seq") public class Book implements Serializable { private Integer id; private String title; private String author; private Customer customer; public Book() { super(); public Book(Integer id, String title, String author) { super(); this.id = id; this.title = title; this.author = author; @ManyToOne @JoinColumn(name = "customer_id") public Customer getcustomer() { return customer; public void setcustomer(customer customer) { this.customer = customer; public String getauthor() { return author; public void setauthor(string author) { this.author = author; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String gettitle() { return title; public void settitle(string title) { this.title = title; @Override public String tostring() { return "Book: " + getid() + " Title " + gettitle() + " Author " + getauthor(); JEE vs Rails Migration Customer Book
/** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import java.util.set; import javax.persistence.cascadetype; import javax.persistence.entity; import javax.persistence.fetchtype; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.onetomany; import javax.persistence.sequencegenerator; import javax.persistence.table; /** * @author hennebrueder * */ @Entity @Table(name="customer") @SequenceGenerator(name="customer_sequence", sequencename="customer_id_seq") public class Customer { private Integer id; private String name; private List books =new ArrayList(); public Customer(){ super(); public Customer(Integer id, String name){ super(); this.id=id; this.name=name; @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedby="customer", targetentity=book.class) public List getbooks() { return books; public void setbooks(list books) { this.books = books; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="customer_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String getname() { return name; public void setname(string name) { this.name = name; @Override public String tostring() { return "Customer: " + getid() + " Name " + getname(); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.stateless; import javax.persistence.entity; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; /** * @author hennebrueder * */ @Stateless public class CustomerDaoImp implements CustomerDao { @PersistenceContext private EntityManager em; public static final String RemoteJNDIName = CustomerDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = CustomerDaoImp.class.getSimpleName() + "/local"; /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#save(de.laliluna.example.ejb.book) */ public void save(customer customer) { em.persist(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#reattach(de.laliluna.example.ejb.book) */ public void merge(customer customer) { em.merge(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findall() */ public List findall() { return em.createquery("from Customer").getResultList(); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findbyid(java.lang.integer) */ public Customer findbyid(integer id) { Customer customer = em.find(customer.class, id); return customer; /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import javax.ejb.stateful; import javax.ejb.stateless; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; import org.apache.log4j.logger; import sun.security.krb5.internal.crypto.bo; /** * @author hennebrueder * */ @Stateless public class BookDaoImp implements BookDao { @PersistenceContext private EntityManager em; private Logger log = Logger.getLogger(this.getClass()); /* * (non-javadoc) * * @see de.laliluna.example.ejb.bookdao#save(de.laliluna.example.ejb.book) */ public void save(book book) { log.debug("persist book: " + book); em.persist(book); public void merge(book book) { em.merge(book); public List findall() { log.debug("find All books"); return em.createquery("from Book").getResultList(); public static final String RemoteJNDIName = BookDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = BookDaoImp.class.getSimpleName() + "/local"; public Book findbyid(integer id) { return em.find(book.class, id); public List findbycustomer(customer customer) { log.debug("find by customer"); return em.createquery("from Book b where b.customer = :customer").setparameter("customer", customer).getresultlist(); package de.laliluna.library; import java.util.list; import javax.ejb.local; import org.jboss.annotation.ejb.localbinding; @Local public interface BookDao { public void save(book book); public void merge(book book); public List findall(); public List findbycustomer(customer customer); public Book findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.local; /** * @author hennebrueder * */ @Local public interface CustomerDao { public void save(customer customer); public void merge(customer customer); public List findall(); public Customer findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.io.serializable; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.joincolumn; import javax.persistence.manytoone; import javax.persistence.sequencegenerator; import javax.persistence.table; import org.hibernate.annotations.genericgenerator; /** * @author hennebrueder * */ @Entity @Table(name = "book") @SequenceGenerator(name = "book_sequence", sequencename = "book_id_seq") public class Book implements Serializable { private Integer id; private String title; private String author; private Customer customer; public Book() { super(); public Book(Integer id, String title, String author) { super(); this.id = id; this.title = title; this.author = author; @ManyToOne @JoinColumn(name = "customer_id") public Customer getcustomer() { return customer; public void setcustomer(customer customer) { this.customer = customer; public String getauthor() { return author; public void setauthor(string author) { this.author = author; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String gettitle() { return title; public void settitle(string title) { this.title = title; @Override public String tostring() { return "Book: " + getid() + " Title " + gettitle() + " Author " + getauthor(); class Customer < ActiveRecord::Base has_many :books end class Book < ActiveRecord::Base belongs_to :customer end class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end JEE vs Rails Migration Customer Book
/** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import java.util.set; import javax.persistence.cascadetype; import javax.persistence.entity; import javax.persistence.fetchtype; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.onetomany; import javax.persistence.sequencegenerator; import javax.persistence.table; /** * @author hennebrueder * */ @Entity @Table(name="customer") @SequenceGenerator(name="customer_sequence", sequencename="customer_id_seq") public class Customer { private Integer id; private String name; private List books =new ArrayList(); public Customer(){ super(); public Customer(Integer id, String name){ super(); this.id=id; this.name=name; @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedby="customer", targetentity=book.class) public List getbooks() { return books; public void setbooks(list books) { this.books = books; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="customer_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String getname() { return name; public void setname(string name) { this.name = name; @Override public String tostring() { return "Customer: " + getid() + " Name " + getname(); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.stateless; import javax.persistence.entity; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; /** * @author hennebrueder * */ @Stateless public class CustomerDaoImp implements CustomerDao { @PersistenceContext private EntityManager em; public static final String RemoteJNDIName = CustomerDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = CustomerDaoImp.class.getSimpleName() + "/local"; /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#save(de.laliluna.example.ejb.book) */ public void save(customer customer) { em.persist(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#reattach(de.laliluna.example.ejb.book) */ public void merge(customer customer) { em.merge(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findall() */ public List findall() { return em.createquery("from Customer").getResultList(); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findbyid(java.lang.integer) */ public Customer findbyid(integer id) { Customer customer = em.find(customer.class, id); return customer; /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import javax.ejb.stateful; import javax.ejb.stateless; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; import org.apache.log4j.logger; import sun.security.krb5.internal.crypto.bo; /** * @author hennebrueder * */ @Stateless public class BookDaoImp implements BookDao { @PersistenceContext private EntityManager em; private Logger log = Logger.getLogger(this.getClass()); /* * (non-javadoc) * * @see de.laliluna.example.ejb.bookdao#save(de.laliluna.example.ejb.book) */ public void save(book book) { log.debug("persist book: " + book); em.persist(book); public void merge(book book) { em.merge(book); public List findall() { log.debug("find All books"); return em.createquery("from Book").getResultList(); public static final String RemoteJNDIName = BookDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = BookDaoImp.class.getSimpleName() + "/local"; public Book findbyid(integer id) { return em.find(book.class, id); public List findbycustomer(customer customer) { log.debug("find by customer"); return em.createquery("from Book b where b.customer = :customer").setparameter("customer", customer).getresultlist(); package de.laliluna.library; import java.util.list; import javax.ejb.local; import org.jboss.annotation.ejb.localbinding; @Local public interface BookDao { public void save(book book); public void merge(book book); public List findall(); public List findbycustomer(customer customer); public Book findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.local; /** * @author hennebrueder * */ @Local public interface CustomerDao { public void save(customer customer); public void merge(customer customer); public List findall(); public Customer findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.io.serializable; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.joincolumn; import javax.persistence.manytoone; import javax.persistence.sequencegenerator; import javax.persistence.table; import org.hibernate.annotations.genericgenerator; /** * @author hennebrueder * */ @Entity @Table(name = "book") @SequenceGenerator(name = "book_sequence", sequencename = "book_id_seq") public class Book implements Serializable { private Integer id; private String title; private String author; private Customer customer; public Book() { super(); public Book(Integer id, String title, String author) { super(); this.id = id; this.title = title; this.author = author; @ManyToOne @JoinColumn(name = "customer_id") public Customer getcustomer() { return customer; public void setcustomer(customer customer) { this.customer = customer; public String getauthor() { return author; public void setauthor(string author) { this.author = author; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String gettitle() { return title; public void settitle(string title) { this.title = title; @Override public String tostring() { return "Book: " + getid() + " Title " + gettitle() + " Author " + getauthor(); class Customer < ActiveRecord::Base has_many :books end class Book < ActiveRecord::Base belongs_to :customer end class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end JEE vs Rails Migration Customer Book Conventions at work!
Signal / Noise
Signal / Noise public void testbook() { Book book = new Book(null,"My first bean book", "Sebastian"); em.persist(book); Book book2 = new Book(null,"another book", "Paul"); em.persist(book2); Book book3 = new Book(null,"EJB 3 developer guide","sebastian"); em.persist(book3); [..] def test_book book = Book.create(:name => "My first bean book", :author => "Sebastian") book2 = Book.create(:name => "another book", :author => "Paul") book3 = Book.create(:name => "EJB 3 dev guide", :author => "Sebastian") [..]
Signal / Noise public void testbook() { Book book = new Book(null,"My first bean book", "Sebastian"); em.persist(book); Book book2 = new Book(null,"another book", "Paul"); em.persist(book2); Book book3 = new Book(null,"EJB 3 developer guide","sebastian"); em.persist(book3); [..] def test_book book = Book.create(:name => "My first bean book", :author => "Sebastian") book2 = Book.create(:name => "another book", :author => "Paul") book3 = Book.create(:name => "EJB 3 dev guide", :author => "Sebastian") [..]
Signal / Noise [..] System.out.println("list some books"); List somebooks = em.createquery("from Book b where b.author=:name").setparameter("name", "Sebastian").getResultList(); for (Iterator iter = somebooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); System.out.println("list all books"); List allbooks = em.createquery("from Book").getResultList(); for (Iterator iter = allbooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); [..] puts "list some books" Book.find_all_by_author("Sebastian").each { book puts book.inspect puts "list all books" Book.find(:all).each { book puts book.inspect
Signal / Noise [..] System.out.println("list some books"); List somebooks = em.createquery("from Book b where b.author=:name").setparameter("name", "Sebastian").getResultList(); for (Iterator iter = somebooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); System.out.println("list all books"); List allbooks = em.createquery("from Book").getResultList(); for (Iterator iter = allbooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); [..] puts "list some books" Book.find_all_by_author("Sebastian").each { book puts book.inspect puts "list all books" Book.find(:all).each { book puts book.inspect
Signal / Noise [..] System.out.println("list some books"); List somebooks = em.createquery("from Book b where b.author=:name").setparameter("name", "Sebastian").getResultList(); for (Iterator iter = somebooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); JDK 1.5 to the rescue (Generics, foreach) System.out.println("list all books"); List allbooks = em.createquery("from Book").getResultList(); for (Iterator iter = allbooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); [..] puts "list some books" Book.find_all_by_author("Sebastian").each { book puts book.inspect puts "list all books" Book.find(:all).each { book puts book.inspect
Signal / Noise public void testrelation() { [..] Drei Books und zwei Customers angelegt customer1.getbooks().add(book); book.setcustomer(customer1); customer2.getbooks().add(book2); customer2.getbooks().add(book3); [..] Drei Books und zwei Customers angelegt customer1.books << book customer2.books << [book2, book3]
Signal / Noise public void testrelation() { [..] Drei Books und zwei Customers angelegt customer1.getbooks().add(book); book.setcustomer(customer1); customer2.getbooks().add(book2); customer2.getbooks().add(book3); [..] Drei Books und zwei Customers angelegt customer1.books << book customer2.books << [book2, book3]
Und mehr... class Book < ActiveRecord::Base belongs_to :customer has_many :chapters has_many :sections, :through => :chapters validates_presence_of :author validates_uniqueness_of :name validates_length_of :name, :within => 6..20, :too_long => "pick shorter name", :too_short => "pick longer name" end
Batteries included Rails bringt einiges mit: Struktur Build Testunterstützung Entwicklungs-, Test- und Produktionsumgebung Kein eigenes Denken notwendig Skripte und Automatismen verwenden gleiche Lokationen
Applikation
Applikation
Applikation
Applikation
Applikation
Applikation
Applikation
Applikation
Applikation
Applikation
Umgebung / Konfiguration
Umgebung / Konfiguration
Umgebung / Konfiguration
Umgebung / Konfiguration
Umgebung / Konfiguration
Umgebung / Konfiguration
Umgebung / Konfiguration
Umgebung / Konfiguration
Umgebung / Konfiguration
Umgebung / Konfiguration
Static Content / Skripte
Static Content / Skripte
Static Content / Skripte
Static Content / Skripte
Static Content / Skripte
Static Content / Skripte
Static Content / Skripte
Static Content / Skripte
Test
Test
Test
Test
Test
Test
Test
Test
wie geht s weiter?
Why The Lucky Stiff s: http://tryruby.hobix.com/ Inklusive Tutorial
A language that doesn t affect the way you think about programming is not worth knowing Alan Perlis
A language that doesn t affect the way you think about programming is not worth knowing Alan Perlis Jim Weirich s: 10 Things Every Java Programmer Should Now About Ruby http://onestepback.org/articles/10things/ Viele Dinge in dieser Präsentation dort geklaut.
Pickaxe 2nd edition Umfassend
The Ruby Way Umfassend Detailliert Zweites Buch?
Ruby for Rails Metaprogrammierung
Creating a Weblog in 15 Minutes http://media.rubyonrails.org/video/rails_take2_with_sound.mov
Agile Web Development with Rails (AWDR) 2nd Edition in Vorbereitung 1st Edition auch in Deutsch erhältlich
Rapid Web Development mit Ruby on Rails Deutsch 2nd Edition gerade erschienen
Weiterführend
http://rubyonrails.org http://ruby-lang.org
... und so lebten sie...
... glücklich...
... bis an s Ende ihrer Tage.
Danke! The text of this presentation is licensed under the Creative Commons License, Attribution-ShareAlike 2.5. As I don t have all the rights to the images in this presentation, the images and the Java source code are not covered by this license. I would also like to thank Babie Tanaka and the flickr users letioux and candiedwomanire that granted me the right to use their images. This work is licensed under the Creative Commons Attribution-ShareAlike 2.5 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.5/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.