DescriptionTo make it simple, this code is the Controller Packet corresponding to a View with multiple tabs. All but one of these tabs are showing a list of dependent entries. This Construction was once a single class, that did everything and I thought Why not refactor that thing?So I began to extract functionality. Then I realized: Hey the @SessionScoped on this thing makes it harder than it should be and moved to @ConversationScoped and @RequestScoped respectively. By the way, the *Distributor businessInterface is a wrapper for operating on the Data-Layer Services, that were subject of a previous question of mine. Even though there is no real business Logic there, there was a need to refactor it out to clarify the usage of these classes. (They were also responsible for that, and thus violated SRP)...The Pages-class mentioned in all these redirects contains constant Strings that are navigation rules for JSF.Did I do well?Class Summary (331 lines in 6 files, making a total of 8985 bytes)CustomerDetailsAddressTabController.java: Responsible for all that's happening in the Address Tab of the View.CustomerDetailsContactPersonTabController.java: Responsible for ... ContactPerson Tab of the View.CustomerDetailsContractTabController.java: .... Contract Tab (you get it, right?)CustomerDetailsController.java: This one is different. He keeps the current instance of Customer in the Conversation. That's why he is the first with @ConversationScopedCustomerDetailsProjectsTabController.java: Projects Tab...CustomerDetailsTabChangeController.java: This one is also different. He keeps track of which Tab is currently active in the View. Thus he's also @ConversationScoped. CodeCustomerDetailsAddressTabController.java: (74 lines, 2009 bytes)@Named@ConversationScopedpublic class CustomerDetailsAddressTabController implements Serializable {    private static final long serialVersionUID = 3857482696303153934L;    @Inject    IAddressService addressService;    @Inject    CustomerDetailsController customerDetailsController;    @Inject    AddressEditController addressEditController;    @Inject    Resources resources;    public void promoteToMainLocation(long newMainId) {        try {            addressService.promoteToMainAddress(newMainId);            customerDetailsController.reloadCurrentCustomer();        } catch (DataLayerLockException e) {            resources                    .produceFacesContext()                    .addMessage(                            null,                            new FacesMessage(FacesMessage.SEVERITY_ERROR,                                    Error:,                                    Some meaningful german error message I censored ;)));        }    }    public String editAddress(long addrId) {        redirectToAddressView(addrId);        return Pages.ADDRESS_EDIT;    }    public String deleteAddress(long addrId) {        processDeleteAddress(addrId);        return Pages.CUSTOMER_DETAILS;    }    private void processDeleteAddress(long addrId) {        addressService.delete(addrId);        customerDetailsController.reloadCurrentCustomer();    }    public String addAddress() {        redirectToAddressView(0);        return Pages.ADDRESS_EDIT;    }    public void redirectToAddressView(long addressId) {        addressEditController.recieveAddress(addressId,                customerDetailsController.getCustomerId(), Pages.CUSTOMER_DETAILS);    }}CustomerDetailsContactPersonTabController.java: (49 lines, 1434 bytes)@Named@RequestScopedpublic class CustomerDetailsContactPersonTabController implements Serializable {    private static final long serialVersionUID = 485782696303153934L;    @Inject    ContactPersonEditController contactPersonEditController;    @Inject    CustomerDetailsController customerDetailsController;    @Inject    ContactPersonDistributor businessInterface;    public String addContactPerson() {        return redirectToContactPersonView(0);    }    public String editContactPerson(final long contactPersonId) {        return redirectToContactPersonView(contactPersonId);    }    private String redirectToContactPersonView(final long contactPersonId) {        contactPersonEditController.recieveContactPersonById(contactPersonId,                customerDetailsController.getCustomerId(),                Pages.CUSTOMER_DETAILS);        return Pages.CONTACTPERSON_EDIT;    }    public String deleteContactPerson(final long contactPersonId) {        businessInterface.delete(contactPersonId);        customerDetailsController.reloadCurrentCustomer();        return Pages.CUSTOMER_DETAILS;    }}CustomerDetailsContractTabController.java: (46 lines, 1350 bytes)@Named@RequestScopedpublic class CustomerDetailsContractTabController implements Serializable {    private static final long serialVersionUID = 4857482696383153934L;    @Inject    ContractEditController contractEditController;    @Inject    CustomerDetailsController customerDetailsController;    @Inject    ContractDistributor businessInterface;    public String addContract() {        contractEditController.recieveCustomerToEditContracts(                customerDetailsController.getCustomerId(), 0l,                Pages.CUSTOMER_DETAILS);        return Pages.CONTRACT_EDIT;    }    public String editContract(final long contractId) {        contractEditController.recieveCustomerToEditContracts(                customerDetailsController.getCustomerId(), contractId,                Pages.CUSTOMER_DETAILS);        return Pages.CONTRACT_EDIT;    }    public String deleteContract(final long contractId) {        businessInterface.delete(contractId);        customerDetailsController.reloadCurrentCustomer();        return Pages.CUSTOMER_DETAILS;    }}CustomerDetailsController.java: (66 lines, 1578 bytes)@Named@ConversationScopedpublic class CustomerDetailsController implements Serializable {    private static final long serialVersionUID = 48574826963021334L;    private Customer customer = new Customer();    @Inject    Conversation conversation;    @Inject    CustomerDetailsTabChangeController tabController;    @Inject    CustomerDistributor businessInterface;    @PostConstruct    public void init() {        if (!conversation.isTransient()) {            conversation.end();        }        conversation.setTimeout(120000);        conversation.begin();    }    @PreDestroy    public void close() {        conversation.end();    }    public void recieveCustomerById(final long id) {        this.customer = businessInterface.loadSingle(id);        tabController.setActiveTab(0);    }    public void reloadCurrentCustomer() {        if (this.customer != null && !(this.customer.getId() <= 0)) {            recieveCustomerById(this.customer.getId());        }    }    public Customer getCustomer() {        return customer;    }    public long getCustomerId() {        return customer.getId();    }}CustomerDetailsProjectsTabController.java: (66 lines, 1866 bytes)@Named@RequestScopedpublic class CustomerDetailsProjectsTabController implements Serializable {    private static final long serialVersionUID = 485734534533153934L;    @Inject    ProjectEditController projectEditController;    @Inject    CustomerDetailsController customerDetailsController;    @Inject    CustomerListController customerListController;    @Inject    ProjectDetailsController projectDetailsController;    @Inject    ProjectDistributor businessInterface;    public String addProject() {        return redirectToProjectView(0);    }    public String editProject(final long projectId) {        return redirectToProjectView(projectId);    }    private String redirectToProjectView(final long projectId) {        projectEditController.recieveCustomerToEditProjects(projectId,                customerDetailsController.getCustomerId(),                Pages.CUSTOMER_DETAILS);        return Pages.PROJECT_EDIT;    }    public String deleteProject(final long projectId) {        try {            businessInterface.delete(projectId);        } catch (IllegalArgumentException ent) {            // that one was already deleted.        }        return Pages.CUSTOMER_DETAILS;    }    public String showProjectDetails(final long projectId) {        customerDetailsController.recieveCustomerById(customerDetailsController                .getCustomerId());        projectDetailsController.recieveProject(projectId);        return Pages.PROJECT_DETAILS;    }}CustomerDetailsTabChangeController.java: (30 lines, 748 bytes)@Named@ConversationScopedpublic class CustomerDetailsTabChangeController implements Serializable {    private static final long serialVersionUID = 48574825445153934L;    private int index;    public int getActiveTab() {        return index;    }    public void setActiveTab(int index) {        this.index = index;    }    public void onTabChange(TabChangeEvent event) {        TabView tabView = (TabView) event.getComponent();        index = tabView.getChildren().indexOf(event.getTab());    }}QuestionsScoping: Can that be improved further? Where could I reduce further, to save even more system resources ;) (the larger the scope, the more difficult it is to maintain)Names: Are these names easily understandable?Anything elseI'd also like you to not mention the String error message, I know that one needs a Constant, but as this is still in development, I decided not to extract that yet ;)Also I gladly provide any further required information ;)
Show Details of an Object while allowing interactions with it and dependent objects
java;jsf 2
Scoping :In your controllers are all your services default scoped.In mine humble oppinion make them private, if you wish to have the default scope make getters and setters default scope.Why: You easily can forget the private before a global variable but getters/setters are mostly autogenerated public so normally when these are not public it's ment to be.Final's :What is looking odd is that in CustomerDetailsAddressTabController.java you don't have the long addrId marked as final as you do that in your other controllers.Error handling :} catch (DataLayerLockException e) {    resources            .produceFacesContext()            .addMessage(                    null,                    new FacesMessage(FacesMessage.SEVERITY_ERROR,                            Error:,                            Some meaningful Error message ;)));}A bigger problem here is that you don't log the DataLayerLockException.It vanish in thin air cause you don't use the e in the catch. Succes with finding the problem at that time.