We write an Eclipse client to the database using hibernate and fishbolt technologies

    This and other examples are available for download here.

    Plugin - data model


    In this section, we create a separate eclise plugin that will contain a data model (to separate data from the user interface is a good tone, as we know)

    Create a plugin


    After creating the plugin, we will write the necessary dependencies:
    And add a line to the file MANIFEST.MF(to use a single class loader, which is required when working with hibernate libraries):
    Eclipse-RegisterBuddy: org.fishbolt.model.hibernate.annotations


    Create data object classes and data object managers


    Department Data Object: Department Data Object Manager : Employee Data Object : Employee Data Object Manager:
    /**
    * Data object presenting department
    */
    @DisplayLabel("Department")
    @ImageResource("department.gif")
    @Entity
    @Tuplizer(impl = CompanyModelTuplizer.class)
    @AccessType("org.fishbolt.model.hibernate.FieldAccessor")
    public class Department 
      extends HDataObject {


      @Id
      @GeneratedValue
      @DisplayLabel("Identity")
      public final static FieldDeclaration id = 
        new FieldDeclaration(Department.class);

      @ObjectPresentationField
      @Column(unique=true, nullable=false)
      @DisplayLabel("Name")
      @Width(250)
      public final static FieldDeclaration name = 
        new FieldDeclaration(Department.class);


      @DisplayLabel("Employees")
      @Relation(inverse="department")
        @OneToMany(targetEntity=Employee.class)
        @JoinColumn(name="department")
      public final static FieldDeclaration> employees = 
        new FieldDeclaration>(Department.class);
      
      public Department(DepartmentManager manager) {
        super(manager);
      }
      
      public Department() {
        super();
      }
    }


    /**
     * Manager class for {@link Department} data object.
     */
    public class DepartmentManager 
      extends HDataObjectManager{
      
      /**
       * Constructor inherited from the super class
       */
      public DepartmentManager(IDataModel dataModel,
          ObjectDescriptor objectDescriptor) {
        super(dataModel, objectDescriptor);
      }

      /**
       * Searches for a department by its name
       * @param name - the name of the department to search for
       * @return department or null
       */
      public Department findDepartment(String name){
        String hql = "from Department where name=?";
        QueryUniqueResultCommand cmd = 
          new QueryUniqueResultCommand(hql);
        cmd.setParameters(new Parameter(name));
        return this.getModel().processCommand(cmd);
      }
    }


    /**
     * Data object presenting employee
     */ 
    @DisplayLabel("Employee")
    @ImageResource("employee.gif")
    @Entity
    @Tuplizer(impl = CompanyModelTuplizer.class)
    @AccessType("org.fishbolt.model.hibernate.FieldAccessor")
    public class Employee extends HDataObject {
      
      @Id
      @GeneratedValue
      @DisplayLabel("Identity")
      public final static FieldDeclaration id = 
        new FieldDeclaration(Employee.class);

      @Transient
      @ObjectPresentationField
      @DisplayLabel("Name")
      @Width(250)
      public final static FieldDeclaration name = 
        new FieldDeclaration(Employee.class);

      @Column(nullable=false)
      @DisplayLabel("First Name")
      public final static FieldDeclaration firstName = 
        new FieldDeclaration(Employee.class);
      
      @Column(nullable=false)
      @DisplayLabel("Last Name")
      public final static FieldDeclaration lastName = 
        new FieldDeclaration(Employee.class);
      
      @DisplayLabel("Phone Number")
      public final static FieldDeclaration phoneNumber = 
        new FieldDeclaration(Employee.class);
      
      @SimpleDateFormatPresentation("dd/MM/yyyy")
      @DisplayLabel("Birthday")
      public final static FieldDeclaration birthday = 
        new FieldDeclaration(Employee.class);

      @DisplayLabel("Salary")
      @Column(nullable=false)
      @DecimalFormatPresentation("#,##0.00")
      @PresentationDecorator(prefix="$ ")
      public final static FieldDeclaration salary = 
        new FieldDeclaration(Employee.class);
      
      @DisplayLabel("Health")
      @NumberFormatPresentation(NumberFormatInstance.percent)
      public final static FieldDeclaration health = 
        new FieldDeclaration(Employee.class);
      
      @DisplayLabel("Department")
      @Relation(inverse="employees")
      @ManyToOne(optional=false)
      @JoinColumn(name="department")
      public final static FieldDeclaration department = 
        new FieldDeclaration(Employee.class);
      
      public Employee(EmployeeManager manager) {
        super(manager);
      }
      
      public Employee() {
        super();
      }
    }


    /**
     * Manager class for {@link Employee} data object.
     */
    public class EmployeeManager 
      extends HDataObjectManager{
      
      /**
       * Constructor inherited from the super class
       */
      public EmployeeManager(IDataModel dataModel,
          ObjectDescriptor objectDescriptor) {
        super(dataModel, objectDescriptor);
      }

      /**
       * Searches for an employee among all employees of a company
       * @param firstName - employee's first name
       * @param lastName - employee's last name
       * @return List of employees
       */
      public List findEmployee(String firstName,String lastName){
        String hql = "from Employee where firstName=? and lastName = ?";
        QueryListCommand cmd = new QueryListCommand(hql);
        cmd.setParameters(
            new Parameter(firstName),
            new Parameter(lastName));
        return this.getModel().processCommand(cmd);
      }
      
      /**
       * Searches for an employee in a department 
         * @param firstName - employee's first name
         * @param lastName - employee's last name
       * @param department
       * @return List of employees
       */
      public List findEmployee(String firstName,String lastName, Department department){
        String hql = "from Employee where firstName=? and lastName=? and department=?";
        QueryListCommand cmd = new QueryListCommand(hql);
        cmd.setParameters(
          new Parameter(firstName),
          new Parameter(lastName),
          new Parameter(department));
        return this.getModel().processCommand(cmd);
      }
    }



    Declaring a data model class



    /**
     * Company model class
     */
    public class CompanyModel extends DataModel {
      
      public final static 
        ObjectDescriptor employee = 
          new EObjectDescriptor(CompanyModel.class);
      
      public final static 
        ObjectDescriptor department = 
          new EObjectDescriptor(CompanyModel.class);
      
      public static ModelDescriptor getDescriptor(){
        return CompanyModel.department.getModelDescriptor();
      }
      
      private static CompanyModel instance;
      
      public static CompanyModel getInstance(){
        return (instance == null) ? 
            instance = new CompanyModel(getDescriptor()) : 
              instance;
      }

      private CompanyModel(ModelDescriptor modelDescriptor) {
        super(modelDescriptor);
      }  
    }



    Customize Hibernate


    Let's create some Tuplizer-class (mentioned in the annotation of the classes of data objects of the same name): create
    public class CompanyModelTuplizer extends DataObjectTuplizer {

      /**
       * Constructor inherited from the super class
       */
      public CompanyModelTuplizer(EntityMetamodel entityMetamodel, 
          PersistentClass mappedEntity) {
        super(entityMetamodel, mappedEntity);
      }

      @Override
      protected ModelDescriptor getModelDescriptor() {
        return CompanyModel.getDescriptor();
      }
    }

    hibernate.cfg.xml

      "-//Hibernate/Hibernate Configuration DTD//EN"
      "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
      

        
          
            org.hibernate.dialect.PostgreSQLDialect
          
          
            org.postgresql.Driver
          
          
            jdbc:postgresql://localhost/company
          
          
            postgres
          
          
            ********
          
          
        
        
        






    Calculated fields


    The employee data object contains a field name. This field is calculated and, accordingly, is not reflected in the database. Below, we implement an algorithm for calculating this field: We associate the implemented calculation algorithm with a data field in the code
    public class EmployeeFullNameCalculation 
      implements IFieldCalculation {
      
      public FieldPath[] getInfluencingPaths(FieldDescriptor dependent) {
        return new FieldPath[]{
            new FieldPath(true, CompanyModel.employee,Employee.firstName),
            new FieldPath(true, CompanyModel.employee,Employee.lastName)
          };
      }

      public String evaluateValue(IDataField toEvaluate) {
        Employee employee = (Employee)toEvaluate.getDataObject();
        return ModelUtil.getValue(employee,Employee.firstName)+
        " " +  ModelUtil.getValue(employee,Employee.lastName);
      }
    }


    public class CompanyCalculationProviderFactory 
      extends FieldCalculationProviderFactorySafe{

      /**
       * Binds calculated fields with calculation classes
       */
      @Override
      protected void bindCalculations() {
        // binding Employee.name with EmployeeFullNameCalculation
        bindCalculation(CompanyModel.employee,Employee.name, 
            new EmployeeFullNameCalculation());
        
      }
    }



    Plugin manifest changes


    We register the factory providers - declare the extension of the point ModelAdapterFactory: The file plugin.xmllooks as follows: Export the packages: And add the driver library to the database:



           point="org.fishbolt.model.ModelAdapterFactory">
         
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
        

     






    The plugin as a result




    Create database tables


    Let's create the company database (Postgres - server). And create the tables:
    CREATE TABLE department
    (
     id integer NOT NULL,
     name character varying(255) NOT NULL,
     CONSTRAINT department_pkey PRIMARY KEY (id),
     CONSTRAINT department_name_key UNIQUE (name)
    )

    CREATE TABLE employee
    (
     id integer NOT NULL,
     firstname character varying(255) NOT NULL,
     lastname character varying(255) NOT NULL,
     phonenumber character varying(255),
     birthday date,
     health double precision,
     parttime boolean,
     salary numeric(19,2),
     department integer NOT NULL,
     CONSTRAINT employee_pkey PRIMARY KEY (id),
     CONSTRAINT fk4afd4acec0414ee2 FOREIGN KEY (department)
      REFERENCES department (id)
    )



    Plugin - user interface


    We create a user interface plugin and add dependencies. As we can see, among the dependencies is the previously created plugin - data model ( example.org.fishbolt.model.hibernate.annotations)

    Wizard for creating data objects


    Create wizard classes to create a data object. Below is the wizard code for the employee data object: Register the corresponding extension. The first page of the wizard for creating an employee type object is as follows: Add the code for the user interface command (UI action), which opens the wizard's dialog for creating the employee object "
    /**
     * Wizard for adding new employees
     */
    public class NewEmployeeWizard extends ObjectNewWizard {

      public NewEmployeeWizard() {
        // indicating the descriptor of a data object
        // whose instances will be created by the wizard
        super(CompanyModel.employee);
      }
      
      @Override
      protected IDataModel getDataModel(IWorkbench workbench, 
          IStructuredSelection selection) {
        // providing a reference to the data model
        // to which new Employee instances will be added
        return CompanyModel.getInstance();
      }

      @SuppressWarnings("unchecked")
      @Override
      public void init(IWorkbench workbench, 
          IStructuredSelection selection){
        super.init(workbench, selection);
        // setting a default value to Employee.department
        Object selectionObject = selection.getFirstElement();
        if (selectionObject instanceof Department){
          ModelUtil.setValue(this.wizardObject,
              Employee.department,(Department)selectionObject);
        }

        String name = 
          LabelProvider.getDisplayLabel(CompanyModel.employee);
        
        // adding pages for step-by-step creation of Employee instances
        this.addPage(
            new ObjectSimpleWizardPage(name,name,null,
            Employee.firstName,
            Employee.lastName,
            Employee.department,
            Employee.phoneNumber));
        this.addPage(
            new ObjectSimpleWizardPage(name,name,null,
            Employee.birthday,
            Employee.salary,
            Employee.health));
      }
    }


    public class OpenNewEmployeeWizardAction extends OpenNewWizardAction {

      @SuppressWarnings("unchecked")
      public OpenNewEmployeeWizardAction(ViewerController controller) {
        super(controller, "New Employee...","Creates a new employee");
      }

      @Override
      public INewWizard getNewWizard() {
        return new NewEmployeeWizard();
      }
      
      @Override
      public void updateEnable() {
        this.setEnabled(getActionObject() instanceof Department);
      }
    }



    Editor for data objects


    Создадим классы фабрик редакторов для объектов данных
    /**
     * EditorFactory for Employees
     */
    public class EmployeeEditorFactory extends EditorFactory {

      EmployeeEditorFactory() {
        // Indicating an Employee object via its descriptor
        // and creating editor pages    
        super(CompanyModel.employee,
          new SimpleEditorPageFactory(
              "Personal information", 
              Employee.firstName,
              Employee.lastName,
              Employee.phoneNumber,
              Employee.birthday,
              Employee.health),
          new SimpleEditorPageFactory(
              "Department information",
              Employee.department,
              Employee.salary)
        );
      }
    }




    /**
     * EditorFactory for Departments
     */
    public class DepartmentEditorFactory extends EditorFactory {

      DepartmentEditorFactory() {
        // Indicating a Department object via its descriptor
        // and creating editor pages    
        super(CompanyModel.department,
          new SimpleEditorPageFactory(
              LabelProvider.getDisplayLabel(CompanyModel.department), 
              Department.name)
        );
      }
    }

    Нам также необходимо создать класс – провайдер редактора и зарегистрировать его:
    public class CompanyEditorProvider extends EditorProvider {
      
      public CompanyEditorProvider(){
        register(new DepartmentEditorFactory());
        register(new EmployeeEditorFactory());
      }
    }

    И объявить редактор:
    Созданный редактор для объекта типа «Сотрудник» выглядит следующим образом:Добавляем код команды пользовательского интерфейса (UI action), которая открывает редактор для объектов данных
    public class OpenInEditorAction extends OpenEditorAction {

      @SuppressWarnings("unchecked")
      public OpenInEditorAction(ViewerController controller) {
        super("example.model.eclipse.DataObjectEditor", controller);
      }
    }

    Для примера, также добавляем код команды пользовательского интерфейса (UI action), которая открывает редактор для объектов данных в специальной перспективе

    public class OpenInEditorPerspectiveAction extends OpenEditorPerspectiveAction {

      @SuppressWarnings("unchecked")
      public OpenInEditorPerspectiveAction(ViewerController controller) {
        super("example.model.eclipse.perspectives.ObjectEditorPerspective",
            "example.model.eclipse.DataObjectEditor",
            controller);
      }
    }



    Диалог для изменения значения поля данных


    Ниже показан класс диалогового окна, который переводит сотрудника из одного отдела в другой:
    /**
     * Dialog that moves an employee from one department to another
     */
    public class ChangeDepartmentDialog 
      extends Dialog implements IWidgetsContext{
      
      private Employee employee;
      private ContextControllerBinder contextBinder;

      public ChangeDepartmentDialog(Shell parentShell,Employee employee) {
        super(parentShell);
        this.employee = employee;
      }

      /**
       * Returns ContextControllerBinder that binds
       * user interface components with data model components
       * through controllers
       */
      public ContextControllerBinder getContextBinder() {
        return contextBinder == null ? 
            contextBinder = new ContextControllerBinder(this) : contextBinder;
      }

      /**
       * Creates dialog's contents 
       * and binds user interface components with data model components
       */
      @Override  
      protected Control createDialogArea(Composite parent) 
      {
        // dialog title
        parent.getShell().setText(PresenterProvider.getPresentation(employee));
        
        Composite result = new Composite(parent, SWT.NONE);
        result.setLayout(new GridLayout(2, true));

        Label decription = new Label(result, SWT.NULL);
        decription.setLayoutData(
            new GridData(GridData.FILL,GridData.FILL,true,true,2,1));
        decription.setText("To move the employee to another department, " +
            "select the department and press OK.");
        
        // Label presenting the data object field
        Label label = new Label(result, SWT.NULL);
        label.setLayoutData(new GridData());
        
        // Combo presenting data field values
        Combo combo = new Combo(result, SWT.BORDER | SWT.DROP_DOWN);
        combo.setLayoutData(
            new GridData(GridData.FILL,GridData.CENTER,true,false));
      
        ContextControllerBinder binder = getContextBinder();
        // binding Label to FieldDescriptor 
        // (the controller that is responsible for interaction
        // between Label and FieldDescriptor is created automatically)
        binder.bind(label, 
            CompanyModel.employee.getFieldDescriptor(Employee.department));
        // binding data field to Combo 
        // (the controller that is responsible for interaction
        // between data field and Combo is created automatically)
        binder.bind(combo, 
            employee.getDataField(Employee.department));    
        
        return result;
      }


      /**
       * Reacts to changes resulted from user's actions on the UI
       * components (controls) that were bound to data model
       * components using ContextControllerBinder
       */
      @SuppressWarnings("unchecked")
      public void contextWidgetChanged(
          EditableWidgetController controller,
          PresentationException exception) {
        if (exception!= null){
          MessageDialog.openError(this.getShell(), 
              "The value is incorrect.",
              "Please specify a correct value.");
          return;
        }
        Collection> problems 
          = employee.validate(null);
        
        if (problems.isEmpty()) return;
        
        showProblems(problems);
        
        employee.refresh();
      }
      
      /**
       * Shows information about the data object problems
       * @param problems
       */
      protected void showProblems(
          Collection> problems){
        StringBuffer msg = new StringBuffer();
        for (ValidationMessage problem : problems){
          msg.append(problem.getDescription());
          msg.append("\\;n");
        }
        
        MessageDialog.openError(this.getShell(), 
            "The value is incorrect.",msg.toString());
        
      }
      
      
      /**
       * Cancel button handler
       */
      @Override
      protected void cancelPressed() {
        employee.refresh();
        super.cancelPressed();
      }
      
      /**
       * OK button handler  
       */
      @Override
      protected void okPressed() {
        employee.store();
        super.okPressed();
      }
    }

    Так выглядит диалоговое окно для перевода сотрудника из одного отдела в другой:

    Дерево «Отдел» — «Сотрудник»


    Create a tree that shows all departments and their employees: Register the corresponding extension ( ) as a result of our efforts:
    /**
     * Creates a view that contains
     * the tree of departments and employees
     */
    public class DepartmentEmployeesView extends ViewPart {
      
      private TreeViewerController treeController = null;
      
      @Override
      public void createPartControl(Composite parent) {
        // creating a controller for TreeViewer
        treeController = new TreeViewerController(parent);
        // setting layout
        GridData data = new GridData(GridData.FILL,GridData.FILL,true,true);
        treeController.getViewer().getControl().setLayoutData(data);
        
        // Using ColumnData to wrap up data objects to be represented in tree nodes.
        // Data objects are specified through their descriptors
        treeController.setColumnProvider(
            new ColumnProvider(
                new ColumnData(CompanyModel.department).add(CompanyModel.employee)));
        
        // Wrapping data in TreeDataObjects and passing it to the controller.
        // To put it in more details:
        // - indicating data objects to be represented in parent nodes.
        //   In this case, these are objects of the Deparment type.
        //   The Department objects are indicated through their manager (DepartmentManager).
        // - indicating data objects to be represented in child nodes.
        //   They are indicated through a bidirectional association.
        //   In this case, the bidirectional association is expressed by Department.employees
        CompanyModel model = CompanyModel.getInstance();
        DepartmentManager manager = model.getDataObjectManager(CompanyModel.department);
        treeController.setDataObjects(
            new TreeDataObjects(
                new ManagerDataObjects(manager),
                new ChildRelation(CompanyModel.department,Department.employees)));

        // building a context menu for the tree
        ContextMenu menu = new ContextMenu();
        menu.add(new OpenInEditorAction(treeController));
        menu.add(new OpenInEditorPerspectiveAction(treeController));
        menu.add(new OpenNewDepartmentWizardAction(treeController));
        menu.add(new OpenNewEmployeeWizardAction(treeController));
        menu.add(new ChangeEmployeeDepartmentAction(treeController));
        menu.add(new ShowDepartmentEmployeesAction(treeController));
        menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
        menu.add(new RemoveDataObjectAction(treeController));
        treeController.setContextMenu(this.getSite(),menu);
      }

      @Override
      public void setFocus() {
        this.treeController.getViewer().getControl().setFocus();
      }
    }

    org.eclipse.ui.views

    Employee table



    /**
     * Creates a view that contains
     * a table displaying information about employees
     */
    public class EmployeesView extends ViewPart{
      
      private TableViewerController tableController = null;

      /**
       * Opens the view and passes to the controller
       * a collection of Employees to be represented
       * in a table within the view.
       */
      public static void setEmployees(List employess){
        EmployeesView view = getView();
        view.tableController.setDataObjects(
            new CollectionDataObjects(employess));
      }

      /**
       * Opens the view and passes to the controller
       * a collection of Employees to be represented
       * in a table within the view.
       * The collection of Employees is specified via
       * the association with the Department object (Department.employees)
       */  
      public static void setDepartment(Department department){
        EmployeesView view = getView();
        IDataField> field = 
          department.getDataField(Department.employees);
        view.tableController.setDataObjects(new RelationDataObjects(field));
      }
      
      @Override
      public void createPartControl(Composite parent) {
        // Creating a controller
        tableController = new TableViewerController(parent);
        // Setting layout
        GridData data = new GridData(GridData.FILL,GridData.FILL,true,true);
        tableController.getViewer().getControl().setLayoutData(data);
        // Specifying data presentation.
        // Passing to the controller an OddBackgroundColorPresentation instance
        // that pastes the background of even table cells
        // with the color specified. Default is RGB(230,230,255)
        tableController.setDataPresenation(
            new EvenBackgroundColorPresentation(tableController));
        
        // Configuring table columns.
        // Using ColumnData to wrap up data object fields to be represented in tree nodes.
        // (Data object fields are indicated through FieldDeclarations)
        tableController.setColumnProvider(
            new ColumnProvider(
                new ColumnData(CompanyModel.employee,Employee.firstName),
                new ColumnData(CompanyModel.employee,Employee.lastName),
                new ColumnData(CompanyModel.employee,Employee.phoneNumber),
                new ColumnData(CompanyModel.employee,Employee.salary)));
        
        // Adding actions that open a dialog for column selection
        ChangeColumnsAction.registerInMenu(this, tableController);
        ChangeColumnsAction.registerInToolBar(this, tableController);
        
        // adding a context menu
        ContextMenu menu = new ContextMenu();
        menu.add(new OpenInEditorAction(tableController));
        menu.add(new OpenInEditorPerspectiveAction(tableController));
        menu.add(new ChangeEmployeeDepartmentAction(tableController));
        menu.add(new RemoveDataObjectAction(tableController));
        tableController.setContextMenu(this.getSite(),menu);

      }

      @Override
      public void setFocus() {
        this.tableController.getViewer().getControl().setFocus();
      }

      /**
       * Opens EmployeesView
       */  
      private static EmployeesView getView(){
        IWorkbenchPage page = PlatformUI.getWorkbench().
          getActiveWorkbenchWindow().getActivePage();
        EmployeesView result = null;
        try {
          for (IViewReference ref : page.getViewReferences()) {
            if ("example.model.eclipse.views.EmployeesView"
                .equals(ref.getId())) {
              result = (EmployeesView) ref.getView(true);
              break;
            }
          }
          if (result == null) 
            result = (EmployeesView) page.showView(
                "example.model.eclipse.views.EmployeesView");
        } catch (PartInitException e) {
          throw new RuntimeException(e);
        }
        return result;
      }
    }

    Add the extension result:

    Employee Search Bar


    Create a panel that will search for employees by the entered parameters and display the search result in the table.
    public class SearchEmployeeView extends ViewPart
        implements IWidgetsContext{

      private Label firstNameLabel;
      private Text firstName;
      private Label secondNameLabel;
      private Text secondName;
      private Label departmentLabel;
      private DialogChooser department;
      private Button searchButton;
      private ContextControllerBinder contextBinder;
      private SelectionAdapter doSearch = new SelectionAdapter() {
        @Override
        public void widgetSelected(SelectionEvent e) {
          CompanyModel model = CompanyModel.getInstance();
          EmployeeManager manager = model.getDataObjectManager(CompanyModel.employee);
          String first = firstName.getText();
          String second = secondName.getText();
          Department d = department.getObject();
          List

    Also popular now: