Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Introduction

In the first part of the Blog tutorial, you will learn:

...

The model should show up in a window that looks like this:

Image Added

If it didn't show up, the window might have opened behind the main Eclipse window. If that's the case, open the Window menu and select the windows that have Entity Modeler in its name.

...

What we are going to do is to write a simple method that returns the full name of an author, e.g. a method that simply concatenate the first name, a space and the last name of the author. To do so, double-click on Author.java and add the following methods:

Code Block

public String fullName() {
	  return this.firstName() + " " + this.lastName();
	}

Nothing fancy here. Now open BlogEntry.java and add the following method:

Code Block

	@Override
	public void awakeFromInsertion(EOEditingContext editingContext) {
		super.awakeFromInsertion(editingContext);
		NSTimestamp now = new NSTimestamp();
		setCreationDate(now);
		setLastModified(now);
	}

...

Remove the pound char in front of those two properties:

Code Block

#er.migration.migrateAtStartup=true
#er.migration.createTablesIfNecessary=true

After removing the pound char, the two properties should look like this:

Code Block

er.migration.migrateAtStartup=true
er.migration.createTablesIfNecessary=true

You are now ready to start the application so that it creates the database! To do so, right-click on Application.java (in the your.app folder) and select Run As -> WOApplication. In Eclipse's Console tab, you should see some output, including something similar to:

Code Block

BlogRest[62990] INFO  er.extensions.migration.ERXMigrator  - Upgrading BlogModel to version 0 with migration 'your.app.model.migrations.BlogModel0@4743bf3d'
BlogRest[62990] INFO  er.extensions.jdbc.ERXJDBCUtilities  - Executing CREATE TABLE Author(email VARCHAR(100) NOT NULL, firstName VARCHAR(50) NOT NULL, id INTEGER NOT NULL, lastName VARCHAR(50) NOT NULL)
BlogRest[62990] INFO  er.extensions.jdbc.ERXJDBCUtilities  - Executing ALTER TABLE Author ADD PRIMARY KEY (id)
BlogRest[62990] INFO  er.extensions.jdbc.ERXJDBCUtilities  - Executing CREATE TABLE BlogEntry(authorID INTEGER NOT NULL, content TIMESTAMP NOT NULL, creationDate TIMESTAMP NOT NULL, id INTEGER NOT NULL, title VARCHAR(255) NOT NULL)
BlogRest[62990] INFO  er.extensions.jdbc.ERXJDBCUtilities  - Executing ALTER TABLE BlogEntry ADD PRIMARY KEY (id)
BlogRest[62990] INFO  er.extensions.jdbc.ERXJDBCUtilities  - Executing ALTER TABLE BlogEntry ADD CONSTRAINT "FOREIGN_KEY_BLOGENTRY_AUTHORID_AUTHOR_ID" FOREIGN KEY (authorID) REFERENCES Author (id)
BlogRest[62990] DEBUG NSLog  -  evaluateExpression: <er.h2.jdbcadaptor.ERH2PlugIn$H2Expression: "UPDATE _dbupdater SET version = ? WHERE modelname = ?" withBindings: 1:0(version), 2:"BlogModel"(modelName)>

...

Add this method in BlogEntryController:

Code Block

protected ERXKeyFilter filter() {
    ERXKeyFilter personFilter = ERXKeyFilter.filterWithAttributes();
    personFilter.setAnonymousUpdateEnabled(true);

    ERXKeyFilter filter = ERXKeyFilter.filterWithAttributes();
    filter.include(BlogEntry.AUTHOR, personFilter);
    filter.setUnknownKeyIgnored(true);

    return filter;
  }

Now, let's implement the createAction method:

Code Block

public WOActionResults createAction() throws Throwable {
    BlogEntry entry = create(filter());
    editingContext().saveChanges();
    return response(entry, filter());
  }

...

Last step in the controller: implementing the indexAction method. Again, the code is simple:

Code Block

public WOActionResults indexAction() throws Throwable {
    NSArray<BlogEntry> entries = BlogEntry.fetchAllBlogEntries(editingContext());
    return response(entries, filter());
  }

...

A route in ERRest is simply a way to define the URL for the entities and to specify which controller the route should use. When your controller extends from ERXDefaultRouteController, it's easy to register a controller and a route. In Application.java, in the Application constructor, add the following code:

Code Block

ERXRouteRequestHandler restRequestHandler = new ERXRouteRequestHandler();
    restRequestHandler.addDefaultRoutes(BlogEntry.ENTITY_NAME);
    ERXRouteRequestHandler.register(restRequestHandler);
    setDefaultRequestHandler(restRequestHandler);

...

We are now reading to add and list blog postings! Start the application and take notice of the URL. It should be something like _http://yourip:someport/cgi-bin/WebObjects/BlogRest.woa_

Adding posts and authors with curl

...

The response should look this:

Code Block

HTTP/1.0 201 Apple WebObjects
Content-Length: 249
x-webobjects-loadaverage: 0
Content-Type: application/json

{"id":1,"type":"BlogEntry","content":"Some text","creationDate":"2011-12-27T21:59:08Z","title":"First post","author":{"id":1,"type":"Author","email":"probert@macti.ca","firstName":"Pascal","lastName":"Robert"}}

To get a list of blog entries:

Code Block

curl -X GET http://192.168.0.102:52406/cgi-bin/WebObjects/BlogRest.woa/ra/blogEntries.json

...

Now, let's build a HTML view for blog posts (you don't want your readers to get your posts by JSON, right?). Again, we will use convention to make it work easily. Open up BlogEntryController and add the following method:

Code Block

@Override
  protected boolean isAutomaticHtmlRoutingEnabled() {
    return true;
  }

...

The next step to get it to work is to make BlogEntryIndexPage to implement the er.rest.routes.IERXRouteComponent interface.

Code Block

import er.rest.routes.IERXRouteComponent;

public class BlogEntryIndexPage extends WOComponent implements IERXRouteComponent {

So now, the automatic HTML routing will send the request for ra/blogEntries.html to the BlogEntryIndexPage component. But we don't have any content in this component, so let's make a method to fetch all blog entries per creation date in descending order. So in BlogEntryIndexPage.java, add the following method:

Code Block

public NSArray<BlogEntry> entries() {
      EOEditingContext ec = ERXEC.newEditingContext();
      return BlogEntry.fetchAllBlogEntries(ec, BlogEntry.CREATION_DATE.descs());
    }

We need to use that method in a WORepetition, and for that loop, we need a BlogEntry variable to iterate in the list, so add the following code to BlogEntryIndexPage.java:

Code Block

private BlogEntry entryItem;

    public BlogEntry entryItem() {
      return entryItem;
    }

    public void setEntryItem(BlogEntry entryItem) {
      this.entryItem = entryItem;
    }

The Java part is done, so let's add the loop inside the component. Open BlogEntryIndexPage.wo (it's located in the Component folder) and right after the <body> tag, add:

Code Block

<wo:loop list="$entries" item="$entryItem">
      <p><wo:str value="$entryItem.title" /></p>
      <p><wo:str value="$entryItem.author.fullName" /></p>
    </wo:loop>

...

Open BlogEntryShowPage.java and make sure the class implements er.rest.routes.IERXRouteComponent.

Code Block

import er.rest.routes.IERXRouteComponent;

public class BlogEntryShowPage extends WOComponent implements IERXRouteComponent {

We need to add other methods to receive the BlogEntry object from the controller. In BlogEntryShowPage.java, add:

Code Block

private BlogEntry blogEntry;

    @ERXRouteParameter
    public void setBlogEntry(BlogEntry blogEntryFromController) {
      this.blogEntry = blogEntryFromController;
    }

    public BlogEntry blogEntry() {
      return this.blogEntry;
    }

...

The Java part of the work is done, so save the Java class. It's time to work on the component part. Open BlogEntryShowPage.wo and between the <body></body> part, add:

Code Block

<h1><wo:str value="$blogEntry.title" /></h1>
    <p><wo:str value="$blogEntry.content" /></p>
    <p>Created on: <wo:str value="$blogEntry.creationDate" dateformat="%Y/%m/%d" /></p>
    <p>Added by: <wo:str value="$blogEntry.author.fullName" /></p>

Our view component is done, the only thing remaining is a link for the blog entry list (BlogEntryIndexPage) to the view page (BlogEntryShowPage). Save BlogEntryShowPage.wo and open BlogEntryIndexPage.wo. We are going to add a link on the title, you will replace to replace this:

Code Block

<p><wo:str value="$entryItem.title" /></p>

with:

Code Block

<p><wo:ERXRouteLink entityName="BlogEntry" record="$entryItem" action="show"><wo:str value="$entryItem.title" /></wo:ERXRouteLink></p>

...