Adding a new Activity and Place in GWT MVP architecture

Adding a new Activity and Place in GWT MVP architecture

This page describes how to create a new "Activity" and "Place" using GWT's Model View Presenter (MVP) architecture. For details on this architecture, see the Developer Guide page on MVP.

Note: The web client code resides in the /client/web folder under the Platform project in SVN.

Steps

Create and configure the new Entity (if applicable)

Note that this code should be reduced dramatically with the upcoming merge of the Web Client and the Synapse Java Client.

  1. Create the new model object for the entity

    1. ex: org.sagebionetworks.web.shared.Project.java

  2. Configure the displayable columns for the entity

    1. Add properties key names to org.sagebionetworks.web.server.ServerConstants.java

    2. Add the property values to ServerConstants.properties

    3. Add column configuration to ColumnConfigurationV2.xml

  3. Configure editable fields org.sagebionetworks.web.client.widget.editpanels.NodeEditorDisplayHelper.java

    // PROJECT private SpecificNodeTypeDeviation createProjectDeviation() { SpecificNodeTypeDeviation deviation = new SpecificNodeTypeDeviation( NodeType.PROJECT, "Project", DisplayConstants.CREATE_PROJECT_TEXT, DisplayConstants.EDIT_PROJECT_TEXT, Arrays.asList(new String[] {"annotations", "accessControlList", "id", "creationDate", "creator", "parentId", "uri", "etag"}), Arrays.asList(new String[] {"annotations", "accessControlList", "id", "creationDate", "creator", "parentId", "uri", "etag"})); deviation.setKeyToOntology(new StaticOntologies().getAnnotationToOntology()); return deviation; }

Create the new Place

  1. Create a new class that extends Place in the org.sagebionetworks.web.client.place package.

    1. ex: ProjectsHome.java

    2. This class is basically boilerplate code for most places. i.e. the token can be generic. This is not true if you want to have a compound token (i.e. store Dataset id and Layer id in the token).

Create the new View

  1. Create a new view and ViewImpl class in org.sagebionetworks.web.client.view. The View should extend IsWidget, and the ViewImpl should implement its view and extend Composite.

    1. ex: ProjectsHomeView.java and ProjectsHomeViewImpl.java

    2. Add static strings to org.sagebionetworks.web.client.DisplayConstants.java as needed

    3. You need to have your ViewImpl's UiBinder class injected into your ViewImpl's constructor, and call initWidget(binder.createAndBindUi(this));

    4. You might want to inject other useful view-related objects like the Header, Footer, IconsImageBundle, SageImageBundle, etc...

    5. Consider adding a showErrorMessage(String message) method to your View interface.

    6. Consider adding a goTo(Place place) method to the View.Presenter interface if your view will need to directly send the user to another place

  2.  Create a UI Binder xml file in src/main/resources/org/sagebionetworks/web/client/view that corresponds to your viewImpl's class name, but with the ui.xml extension

    1. ex: ProjectsHomeView.ui.xml

Create the Presenter for your View

  1.  Create your Presenter class in org.sagebionetworks.web.client.presenter. This is your "Activity", and it should extend AbstractActivity and implement your View.Presenter interface.

    1. ex: ProjectsHomePresenter.java

    2. Inject your view into the constructor

      1. ex:

        public ProjectsHomePresenter(ProjectsHomeView view)
    3. MAKE SURE to call the view's setPresenter method. This allows your view to communicate with the presenter

      1. this.view.setPresenter(this);
    4. Note: AbstractActivity is a base impl of the Activity interface, which is all that is truly needed to be an "Activity". Not needed here, but good to know.

    5. Views are expensive to create as they instantiate many DOM objects in the browser, thus they are kept as Singletons

  2. Write a test for your Presenter (i.e. ProjectsHomePresenterTest.java). The ViewImpl should not contain any business logic, only display logic, thus no test is required. Make sure to use the Presenter interface in the View interface to delegate business logic (like a goTo(...) place change) to the presenter.

Maps!

There are many, many maps you need to add your entity to to get everything wired together properly:

For new entity types:

  1. Add your new entity to org.sagebionetworks.web.shared.NodeType.java so that the node type is now one that the web ui knows about.

  2. Add your new entity to org.sagebionetworks.web.shared.QueryType.java so that the web ui knows it can query the entity.

  3. Add your new entity to org.sagebionetworks.web.server.servlet.ServiceUtils.java so that http client knows it can fetch it from the repo service.

  4. Add the provider methods to org.sagebionetworks.web.server.ColumnConfigProvider.java so that the web ui can find the column configuration for the new entity

  5. Add the provider methods to the constructor for org.sagebionetworks.web.client.widget.editpanels.NodeEditorDisplayHelper.java so that the web ui can find the configuration for the editable fields.

  6. Add the new provider methods to org.sagebionetworks.web.client.transform.NodeModelCreator and org.sagebionetworks.web.client.transform.NodeModelCreatorImpl.java so that the web ui can know about the new entity creation methods

  7. Add your new entity to the place mapping in org.sagebionetworks.web.client.DisplayUtils.getPlaceForEntity(...) method

    case LAYER: place = new Layer(id, null, false); break;
  8. Add your new entity to the org.sagebionetworks.web.client.DisplayUtils getNodeTypeForEntity(Entity entity) method

For new places (which may or may not involve a brand new entity):

  1. Add your new Place class's Tokenizer to the AppPlaceHistoryMapper.java @WithTokenizers annotation in org.sagebionetworks.web.client.mvp

    ProjectsHome.Tokenizer.class
  2. Map your Place to your Activity (Presenter) in org.sagebionetworks.web.client.mvp.AppActivityMapper.java

    else if (place instanceof ProjectsHome) { // Projects Home ProjectsHomePresenter presenter = ginjector.getProjectsHomePresenter(); presenter.setPlace((ProjectsHome)place); return presenter; }
  3. (Optional) If you want your Place to be visible to unauthenticated users, add the following line to the AppActivityMapper's constructor:

    openAccessPlaces.add(<Your Place Class>.class);
  4. Bind the ViewImpl to the view, and make it a singleton in PortalGinModule.java (in org.sagebionetworks.web.client)

    // ProjectsHomeView_ bind(ProjectsHomeViewImpl.class).in(Singleton.class); bind(ProjectsHomeView.class).to(ProjectsHomeViewImpl.class);
  5. Create a getter in the PortalGinInjector for your Presenter (in org.sagebionetworks.web.client)

    public ProjectsHomePresenter getProjectsHomePresenter();

Testing

  1. Run your presenter test

  2. Stop and then restart your GWT dev server and you'll be good to go.