Vous êtes sur la page 1sur 34

Media Library Tutorial

By Fabre Tristan Prototype version, the 17th of August 2007

Abstract:
This tutorial introduces how to use Jdeveloper 10g, the ADF BC framework and the Oracle 9i RDBMS in order to build a little web application enabling to upload and download files. These files will be kept into the database as BLOB and the interfaces of the app will let to organize these records depending on their extension and a type chosen by the user. An administrator will be able to manage the content of this type list and too the extension and their associated mime-type. Prior to follow these instructions, assume to have successfully installed Jdeveloper (Jdev) 10g and Oracle 9i, and to have created a database (DB) instance.

Content:
I. Building the model layer .................................................................................................... 2 Generating the application skeleton ............................................................................... 2 Making the DB schema .................................................................................................. 3 i. Connecting the DB ..................................................................................................... 3 ii. Building the DB schema ............................................................................................ 4 c. Organizing and configuring the app module.................................................................. 8 i. Generating the Business Components........................................................................ 8 ii. Organizing the Business Components........................................................................ 9 iii. Configuring the Business Components ................................................................ 10 II. Building the controller layer ............................................................................................ 13 a. Generating the interface skeleton ................................................................................. 13 i. Configuring the UserInterface project .................................................................. 13 ii. Building and using the faces-config.xml .............................................................. 13 iii. Adding the source files......................................................................................... 15 b. Coding the needed methods and functions................................................................... 16 i. Controlling the application administrator tasks ....................................................... 16 ii. Controlling the library tasks ..................................................................................... 18 III. Designing the interfaces ............................................................................................... 24 a. Generating the administration page.............................................................................. 24 i. Management of the type list ..................................................................................... 24 ii. Management of the extensions and the mime-types ................................................ 27 b. Generating the library page .......................................................................................... 28 i. Displaying the files................................................................................................... 28 ii. Enabling to upload new files .................................................................................... 29 c. Binding the controllers and refining the display .......................................................... 30 i. On the administration.jspx page ........................................................................... 30 ii. On the Library.jspx page ...................................................................................... 32 a. b.

I. Building the model layer


a. Generating the application skeleton
The first step to perform is to make the schema of the DB and then to save it under Oracle 9I. And before doing that, the future application needs a container to the different files. Building the application skeleton is quite an easy task under Jdev. Open the Application Navigator in the Jdev menu > View, right click on Applications and select New Application. Fill the form to correspond to the following screen:

The creation wizard launches the form enabling the creation of a new project into the app; Enter DataModel and accept the default directory. A simple setting to add is the default package name. For that right click on the new created project and select Project Properties. Select the Project Content facet and change the text field at the bottom of the form: Default package which should be medlib has to be change for medlib.datamodel.

b. Making the DB schema


i. Connecting the DB
In Jdev, open the Connection Navigator window in the Jdev menu > View; right click on the Database folder and then choose New Database Connection. The wizard which is launched includes 4 steps to fill like the followings: Step 1: Choose a name for the new connection and select JDBC. This name will be referenced in this tutorial by the tag <DBConnectionName>., and to help in the understanding of this tutorial, the <DBConnectionName> will be MediaLibraryConnection in all the examples Step 2: Use sys, the sys-password defined during the instance creation and sysdba to fill the username, the password (DEMLIB here) and the role (sysdba). Check the box for Deploy password Step 3: Use Thin for the driver. Depending on the Oracle 9i installation, use localhost, 1521 and the SID name for the Oracle DB instance created. In the examples, SID will be DEMLIB. Step 4: Test the connection. If the test doesnt return Success, go back on the preceding steps on try to find what mistake has been done. NOTE: In a first time, the connection is created for the sys in order to access the SQL*PLUS executable. After creating an empty schema for a specific user, the connection will be modified for allowing access only to this user and this schema. Select the new connection and in the Jdev menus, open Tools > SQL*PLUS. A browser function should be launched to help to find the SQL*PLUS executable. Find it in the Oracle9i_Home\ora92\bin\sqlplusw.exe. When prompting for a password, enter MEDLIB, and then On the SQL*PLUS page, enter: CREATE USER TIF IDENTIFIED BY TIF DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON users; GRANT connect, resource TO TIF; then press Enter to execute it. Now close this window, and right click on the new created connection. Select properties, go on authentication and replace the username and its password by TIF and TIF. Delete the role, go to the Test facet and check if the new connection parameters are correct by testing the connection. NOTE: The browse function enabling to select the SQL*PLUS executable is launched at the first use of Tools > SQL*PLUS, but you can change this location going to Tools > Preferences > Database connections

ii. Building the DB schema


Now, create the database diagram, by right clicking on the new project and selecting New, the database diagram creation wizard is in General > Diagrams. Use MedLibDiagram and medlib.datamodel.diagram as name and package for the new diagram. The proposed schema is simple; a table will contain all the files in a Blob field, it will be associated to a central table which will support the details about each file uploaded. To identify easily the extension and the mime-type to associate, they will be stored in a separate table, and finally by adding a last one which contains a type, the application will allow user to class the uploaded files in different types like Rock music, Administrative documents, Charm pictures, etc.

=> Creating tables


To make this document shorter, only two table creation processes are entirely described here: the DOCS and the DETAILS table. NOTE: If the Component palette is not yet displayed when the MedLibDiagram is opened, go into the Jdev menus at Views > Component palette or click Ctrl+Maj+P. Start by dropping a table from the Component palette and then rename it DOCS by double clicking on the title. Now double click on the table to open the wizard enabling to add fields, constraints, primary and foreign keys on the table. In the Table Information, enter TIF in the Schema. Its important to not forget this step during the creation of all the tables and the sequences. Select Column Information and add two columns by clicking on the green cross. Name the first one DOC_ID and the second DOC_BLOB. With the first one selected choose Number, and choose Blob for the second. Check the box Cannot be null for the two. Now Select the Primary Key Information, and make DOC_ID switching from the left panel to the right one There is neither constraints nor foreign key on this table, also choose OK Drop a new table and rename it DETAILS. Open the wizard: Add six columns with names DETAIL_ID, DETAIL_NAME, DETAIL_EXTENSION, DETAIL_TYPE, DETAIL_DOC and DETAIL_DATE Select Date for DETAIL_DATE, Varchar2 (4000) for DETAIL_NAME and Number for the other columns. Now Select the Primary Key Information, and make DETAIL_ID switching from the left panel to the right one Add a Unique Constraints Information by making DETAIL_NAME switching from the left panel to the right one. That will let to forbidden the save of two files having the same name.

Now add a Foreign Key: Referenced DOCS on constraint DOC_PK and make matching DETAIL_DOC in the local column to DOC_ID in the referenced column on DOCS. Finally choose OK. Add still two tables EXTENSIONS and TYPES, and then edit DETAILS to add their ID in the foreign keys.

=> Creating sequences


On each table, create a sequence: Dont forget to enter TIF in the Schema text field. Drop a sequence on the diagram per table and name it with the name of the table without the S it refers, plus _SEQ. Double click on the sequence to open a new wizard. Use 1 for the Increment and 200 for the Start with. Enter 1 and 999999999 for the Min and the Max value Finally check the box Cache and enter 20 in the associated text field These sequences will enable to generate automatically different ID for each new entry in the different tables. But to use these sequences, some triggers are needed.

=> Conciliating the complete schema to the DB


The complete schema is the following:

When schema is complete, it has to be reconciled to the DB. Automatically, Jdev has built the Offline Database Sources which are an offline copy of the elements contained in the schema. The folder containing these sources should have name MYSCHEMA. Right click on it and choose Generate or Reconcile Objects: Step 1: Switch the 4 table elements except DETAILS (to assume the other tables will exist before trying to create the foreign keys) to the Selected panel. The tables have to be created before trying to generate the sequence. Step 2: Choose CREATE Objects. Functions REPLACE and ALTER can be used when objects already exists in the DB. Step 3: Uncheck Generate SQL Scripts. Checking this option has no consequences on this tutorial and can be done for having a look on the way of SQL generates the DB objects. Step 4: Check Perform Operations Against Database. Choose for Connection the MediaLibraryConnection and for Schema the name given to the DB user which is TIF. Step 5: Check the summary before to accept it. Until clicking on End, the Oracle DB schema TIF is still empty and that action will populate it. Now, complete the table creation by clicking on End and check the pop up message. This message confirms the table creation. Step 6: Now, reconcile the last table DETAILS by repeating step 1 to 5 with switching only this table. Step 7: Finally, reconcile the sequences by repeating the step 1 to 5 with switching only the sequences. NOTE: Its possible to reconcile offline objects to the DB by right clicking on the schema and selecting Generate > Data Definition Language For Database.

=> Creating triggers


On each sequence, the DB needs a trigger to know when use it: Open the Connection Navigator window in the Jdev menu > View, and drilldown the MediaLibraryConnection > TIF > Triggers. Then right click and choose New Trigger Enter ASSIGN_DOC_ID in the Name textfield, select DOC table and check the Insert box before clicking on OK. The new trigger is created on the DOC table. Double click on it in the Triggers folder. That opens it in the principal window. Finally cut and paste the part of the code corresponding to the ASSIGN_DOC_ID trigger from the following:
TRIGGER ASSIGN_DOC_ID BEFORE INSERT ON DOC FOR EACH ROW BEGIN IF :NEW.DOC_ID IS NULL OR :NEW.DOC_ID < 0 THEN SELECT DOC_SEQ.NEXTVAL INTO :NEW.DOC_ID FROM DUAL; END IF; END;

TRIGGER ASSIGN_DETAIL_ID BEFORE INSERT ON DETAILS FOR EACH ROW BEGIN IF :NEW.DETAIL_ID IS NULL OR :NEW.DETAIL_ID < 0 THEN SELECT DETAIL_SEQ.NEXTVAL INTO :NEW.DETAIL_ID FROM DUAL; END IF; END; TRIGGER ASSIGN_EXTENSION_ID BEFORE INSERT ON EXTENSION FOR EACH ROW BEGIN IF :NEW.EXTENSION_ID IS NULL OR :NEW.EXTENSION_ID < 0 THEN SELECT EXTENSION_SEQ.NEXTVAL INTO :NEW.EXTENSION_ID FROM DUAL; END IF; END; TRIGGER ASSIGN_TYPE_ID BEFORE INSERT ON TYPE FOR EACH ROW BEGIN IF :NEW.TYPE_ID IS NULL OR :NEW.TYPE_ID < 0 THEN SELECT TYPE_SEQ.NEXTVAL INTO :NEW.TYPE_ID FROM DUAL; END IF; END;

Build the three others triggers by adapting the preceding steps. In the Connection Navigator window, the existing objects should match the following screen:

c. Organizing and configuring the app module


The Db is ready to use and the Offline Database Sources should reflect it. These sources will be very useful to make the app evolving by adding tables and columns in the existing schema. The next step is to produce the Entity Objects (EO), the View Objects (VO) and the View Link (VL) which will provide the model layer, and then to organize them to build the Application Module (AM).

i. Generating the Business Components


The objective is to obtain the following architecture:

Jdev enables, thanks to the Application Development Framework Business Components (ADF BC), to build very quickly and easily the model layer. Right click on the datamodel package and select new Business Components from Tables: Step 1 creating the EO: Click on the Query button, and switch all the 4 tables into the Selected panel. Step 2 creating the Updatable VO: Switch all the 4 tables into the Selected panel. Step 3 creating the Read-only VO: No read-only VO has to be created. Step 4 creating the AM: Check the box Application Module and enter MedLibModule in the field Name. Step 5 creating the Business Component Diagram: uncheck the box, and click on Next. Step 6 summary: The displayed summary should match the following, if not, cancel the creation and start again the creation at step 1:

ii. Organizing the Business Components


To understand the circulation of the information through the model layer and facilitate future maintenance, a good way is to reorganize the business components.

=> Organizing EO and their corresponding Associations


Select the 4 EO (Details, Docs, Extensions and Types). Right click and choose Refactor > Move. Enter the path medlib.datamodel.entities, click on Ok and accept the creation of the new folder. Select the 3 Associations (DetailsDocFk1Assoc, DetailsExtensionFk1Assoc and DetailsTypeFk1Assoc). Right click and choose Refactor > Move. Enter the path medlib.datamodel.entities.associations, click on Ok and accept the creation of the new folder.

=> Organizing VO and their corresponding VL


Select the 4 VO (DetailsView, DocsView, ExtensionsView and TypesView). Right click and choose Refactor > Move. Enter the path medlib.datamodel.viewobjects, click on Ok and accept the creation of the new folder. Select the 3 VL (DetailsDocFk1Link, DetailsExtensionFk1Link and DetailsTypeFk1Link). Right click and choose Refactor > Move. Enter the path medlib.datamodel.viewobjects.links, click on Ok and accept the creation of the new folder.

The result of this reorganization matches the following screen:

iii. Configuring the Business Components


The Business Components provide a quite easy and fast way to perform a lot of complex tasks like handling the transactions between the database and the model layer or managing the way of displaying the data through the interface.

=> Configuring the EO:


Different tasks can be performed on the EO; the following is a short sample list: Customizing the EO attributes, like fixing the ID of each table to a DBsequence type, adding default values if needed, fixing the labels to display at run time. Adding validation rules to force values to match some regular expressions or to belong to a fixed list Generating associated Java files to add custom code functionalities.

The first task to perform is to fix the ID of each EO on the DBSequence type: Double click on the EO, expand the attribute node and select the ID attribute. Use the Type drop down list to find DBSequence. Keep the other default values, click on Apply then on Ok. Repeat these simple operations for each one of the EO. Now, change the labels to customize the future interface displays: For the Extensions and the Types EO, double click on the EO, expand the attribute node and select one of the non ID attribute. Click on the Control Hints tab. In the Label Text field, enter Extension Name, Type Name, Mimetype or Type Definition depending on the selected attribute. In the Display width field, type 25 (except for the Type Definition where this value has to be fixed to 50) Repeat these simple operations until have fixed Label Text and Display width for each one of the four attributes. Now repeat these steps for the Details EO. DetailName should have label File Name and width = 50. DetailDate take 10 and Upload Date for values.

=> Configuring the VO:


In complex app, many VOs are built on each EO depending on the different operations to carry out. That explain why its possible to refine again the future interface displays; default behaviour for each VO is to take values from the EO but if any value has been set in a VO, it will display it: In the MediaLibrary app, there is no need for specific customization of the VO, but a not yet existing VO is needed. To create it right click on the viewobjects package, and then choose New View Object: Step 1: Just change Name empty field to AllFilesAndDetails and go to the next step Step 2: In the medlib.datamodel.entities package displayed in the left window, find Details and switch it to the right window. Verify the Updatable is checked when the Details in the right panel is selected. Switch the three other EO assuming the Association list is correctly populated and only the Reference box is checked for each of them (default behaviour). Step 3: Switch all the attributes from left to right Step 5: (Just keep default on step 4) Add Types.TYPE_NAME ASC , Extensions.EXTENSION_NAME ASC , Details.DETAIL_NAME ASC in the Order By text field and keep other default values. Click on Finish to create the VO.

=> Building the AM:


The Application Module let the interface interacts via the controllers to the model. The way the VO will be available in the AM has to be configured: Double click on the AM to editing it Get the right panel empty of the nested VO by selecting them one by one and using the blue arrow. The AM is populated by default, but there is no need for these complex relationships (search for master - detail) in the app. Expand the medlib.datamodel.viewobjects package (central panel) to find the AllFilesAndDetails VO, and switch it to the right panel Click on Apply and on Ok. The complete AM looks like the following screen:

NOTE: Its important to save regularly the current progress. The use of Make and Rebuild is another think to keep in mind; java has to be compiled to work.

II. Building the controller layer


a. Generating the interface skeleton
Like in the first part of the tutorial, the application has to be structured in a new project which will contain the files for the interface and the controllers.

i. Configuring the UserInterface project


Right click on the MediaLibrary application and select New Project. In the left panel, choose General > Projects, and select Empty Project in the right panel. Fill the Project Name text field with UserInterface and keep the default value for the directory. Right click on the new created project and choose Project Properties. In the left panel select the Project Content node and at the bottom of the right panel find the Default Package and type medlib.userinterface. Now choose Dependancies in the left panel and check the box DataModel.jpr to assume the two layers are connected together.

ii. Building and using the faces-config.xml


Right click on the UserInterface project and choose New. Drill down the Web Tier node, select the JSF and choose JSP Page Flow in the right panel. After clicking on OK, keep the default values for File Name and Directory Name. The new file is opened in the principal window on the Diagram facet; just open the Component Palette by clicking on Ctrl+Maj+P or by getting in the Jdev menus > View > Component Palette.

=> Imagining the workflow:


By using drag and drop, Jdev enables to build very quickly the complete application navigation and skeleton. Drop two JSF Page onto the diagram. Then drop two JSF Navigation Case going from one page to the second. Finally change the names of the page and the navigation arrows in way to match the following screen shot:

NOTE: The yellow warning signals mean these pages dont yet exist. Have a look on the tab Source, the underlining lines have the same signification.

=> Building a template for the pages:


Building a template is very useful to generate quickly similar pages and so giving an application a unified look and feel.

Right click on the WEB-INF project and choose New. Drill down the Web Tier node, select the JSF and choose JSF JSP: Step 1: Enter template.jspx in the File Name field and add \template to the default entry in Directory Name. Assume to have checked the JSP Document box Step 2: Check Do Not Automatically Step 3: Assume you have selected (in the right panel), the ADF Faces Components, ADF Faces HTML, JSF Core 1.0 and JSF HTML 1.0 libraries. Step 4: Here, you could add a personal touch, but just click on Finish. The new template appears in the principal window. Drop on it the PanelPage component from the ADF Faces Core elements (from Component Palette). Then Drop a MenuBar and two PanelGroup components. These different containers will be use in the pages.

=> Generate the pages and apply the template:


Reopen the faces-config.xml if it was closed. Double click on one of the two pages. That will launch the Cerate JSF JSP wizard with all the correct settings, so just click on next if you want to check the steps, or directly click on Finish. Repeat this action for the second page. NOTE: The yellow warning signals have disappeared. In the Application Navigator, select the template.jspx file. The Structure window shows the content of the file. Find the afh:html node, right click on it and choose Copy. Next find one of the two pages, find the node html, delete it and paste on the f:view the node you have copied. Do the same on the second page.

iii. Adding the source files


The source files will contain all the classes, functions and methods enabling to control the information flow coming from the interface.

=> Using some utility files:


In a first time, its interesting to add some utility files which will provide the future beans some common functions and methods. In the Application Navigator, right click on the Application Sources folder. Then choose in the left panel, the tab General, then in the right panel the Java Class option. Fill the form to match this one:

Repeat these steps two times with using JSFUtils and FileOperations for the class names. Copy the content from appendix to the corresponding Java class.

=> Completing the web.xml:


Add the following tags to the web.xml:
<context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>client</param-value> </context-param> <context-param> <param-name>CpxFileName</param-name> <param-value>dfly.userinterface.DataBindings</param-value> </context-param>

<!-- Maximum memory per request (in bytes) --> <context-param> <param-name>oracle.adf.view.faces.UPLOAD_MAX_MEMORY</param-name> <!-- Use 5,000K --> <param-value>5120000</param-value> </context-param> <!-- Maximum disk per request (in bytes) --> <context-param> <param-name>oracle.adf.view.faces.UPLOAD_MAX_DISK_SPACE</param-name> <!-- Use 500,000K --> <param-value>512000000</param-value> </context-param> <!-- Temporary storage directory --> <context-param> <param-name>oracle.adf.view.faces.UPLOAD_TEMP_DIR</param-name> <param-value>/tmp/ADFUploads/</param-value> </context-param> <filter> <filter-name>adfBindings</filter-name> <filter-class>oracle.adf.model.servlet.ADFBindingFilter</filter-class> </filter> <filter-mapping> <filter-name>adfBindings</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> <filter-mapping> <filter-name>adfBindings</filter-name> <url-pattern>*.jspx</url-pattern> </filter-mapping>

b. Coding the needed methods and functions


Even if the interfaces will be built only in the next chapter, its now time for coding the methods and functions which will be needed to control the interfaces behaviors.

i. Controlling the application administrator tasks


The proposed tasks for the administration will be controlled automatically using some ADF properties. Also the only action which will need a control is the one enabling to switch the display of the page between the type management form and the extension management form.

=> Building the backing bean:


In the Application Navigator window, right click on the package View located in UserInterface > Application Sources > UserInterface. Select New then choose Java Class from the categories General: Use LibraryBean for Name and userinterface.view.backing in the Package field.

The new class is created but has to be declared into the faces-config.xml to be used: Step 1: Open the faces-config.xml in the principal window by a double click on it in the Application Navigator window. Step 2: With the Overview tab selected, choose the Managed beans and click on the button New. Step 3: Enter LibraryBean in the Name field and userinterface.view.backing.LibraryBean in the field Class. This second text can be obtained by using the Browse button and selecting the class LibraryBean. Finally keep the Request scope and the box Generate checked, then press Ok. This bean will have to be bound to the interface context. To enable this, more declarations are needed: With the LibraryBean selected into the Managed Beans panel, expand the Managed Properties panel with the black array and add a new property with the New button. Insert bindings in the Name field and accept the form. Now, with the new Managed properties selected, change the Value in the Managed property panel from null to #{bindings}.

=> Written the needed code:


In order to edit it, open the LibraryBean.java file if it is not already opened: Copy the lines below in the Public Class LibraryBean between the braces:
private BindingContainer bindings; private CorePanelGroup administrationTypesPanelGroup; private CorePanelGroup administrationExtensionsPanelGroup;

Right click on the word bindings, then choose Generate Accessors. Check all the boxes in order to generate the getters and the setters for the three new attributes. The code editor automatically imports the corresponding libraries, also the following lines have been created:
import oracle.adf.view.faces.component.core.layout.CorePanelGroup; import oracle.binding.BindingContainer;

Now write the function enabling to switch the display:


public String administrationSwitchDisplay() { if (this.getAdministrationTypesPanelGroup().isRendered()) { // If the page displays the types management form // Don't display it any more this.getAdministrationTypesPanelGroup().setRendered(false); // And display the extension management form this.getAdministrationExtensionsPanelGroup().setRendered(true); } else { // Else display it this.getAdministrationTypesPanelGroup().setRendered(true); // And don't display the extension management form this.getAdministrationExtensionsPanelGroup().setRendered(false); } return null; // To stay on the same page }

ii. Controlling the library tasks


The library has to enable to download the selected file and to upload new ones. The upload process is composed by a selection in a drop down list for the type to associate to the file and then by the selection of the file itself.

=> Adding the functions for switching the display:


In order to edit it, open the LibraryBean.java file if it is not already opened: Build the following attributes in the LibraryBean class:
private CorePanelGroup LibraryDownloadPanelGroup; private CorePanelHeader LibraryDownloadSelectionPanelHeader; private CorePanelHeader LibraryDownloadConfirmationPanelHeader; private CorePanelGroup LibraryUploadPanelGroup; private CorePanelBox LibraryUploadTypeSelectionPanelheader; private CorePanelBox LibraryUploadFileSelectionPanelHeader;

Generate all the corresponding accessors. The code editor has imported the following class:
import oracle.adf.view.faces.component.core.layout.CorePanelHeader; import oracle.adf.view.faces.component.core.layout.CorePanelBox;

Finally, add the three following functions:


public String librarySwitchDisplay() { if (this.getLibraryDownloadPanelGroup().isRendered()) { this.getLibraryDownloadPanelGroup().setRendered(false); this.getLibraryUploadPanelGroup().setRendered(true); this.getLibraryUploadTypeSelectionPanelbox().setRendered(true); this.getLibraryUploadFileSelectionPanelbox().setRendered(false); } else { this.getLibraryDownloadPanelGroup().setRendered(true); this.getLibraryUploadPanelGroup().setRendered(false); this.getLibraryDownloadSelectionPanelHeader().setRendered(true); this.getLibraryDownloadConfirmationPanelHeader().setRendered(false); } return null; } public String libraryDownloadSwitchDisplay() { if (this.getLibraryDownloadSelectionPanelHeader().isRendered()) { this.getLibraryDownloadSelectionPanelHeader().setRendered(false); this.getLibraryDownloadConfirmationPanelHeader().setRendered(true); } else { this.getLibraryDownloadSelectionPanelHeader().setRendered(true); this.getLibraryDownloadConfirmationPanelHeader().setRendered(false); } return null; }

public String libraryUploadSwtichDisplay() { if (this.getLibraryUploadTypeSelectionPanelheader().isRendered()) { this.getLibraryUploadTypeSelectionPanelheader().setRendered(false); this.getLibraryUploadFileSelectionPanelHeader().setRendered(true); } else { this.getLibraryUploadTypeSelectionPanelheader().setRendered(true); this.getLibraryUploadFileSelectionPanelHeader().setRendered(false); } return null; }

=> Adding controllers for uploading files:


The first step, in order to upload a new file into the library, is to choose in a list the type which will be associated to this file In order to get the selected type, copy the following function:
public Integer findTheSelectedTypeFromList4UploadingNewFile() { DCIteratorBinding typeIter = ADFUtils.getIterator("TypesView1"); Row r = typeIter.getCurrentRow(); Integer typeID = new Integer(0).valueOf((String)r.getAttribute("TypeId").toString()); return typeID; }

To confirm the choice and going to the page enabling to select the file to upload, the simplest solution is to use the preceding libraryUploadSwitchDisplay function. Now add two functions to extract the name and the extension of the selected file:
/** * Enable to read the name a document by cuting its extension * @param filename The complete name of a document * @return String Return the name of the document without its extension */ public static String findExactName(String filename) { String[] tests = filename.toLowerCase().split("\\."); Integer i = null; for (i = 1; i < tests.length - 1; i++) { tests[i] = tests[i - 1].concat("." + tests[i]); } return tests[tests.length - 2]; } /** * Enable to read the extension of a document by cuting its name * @param fileName The complete extension of a document with the initial dot * @return String Return the extension of the document without its name */ public static String getExtensionFromFileName(String fileName) { String[] tests = fileName.toLowerCase().split("\\."); return "." + tests[tests.length - 1]; }

To simplify the use of the library, its very useful to control the extensions of the uploaded files and to create them if they are not yet existing:
/** * Add an extension to the existing one in the database * @param fileExtension * @return the new extension Id */ public Integer createAnExtension(String fileExtension) { DBSequence newExtensionId = new DBSequence("EXTENSION_SEQ", ADFUtils.getApplicationModule("MedLibModule")); DCBindingContainer dcBindings = (DCBindingContainer)ADFUtils.findBindingContainer(getBindings(), "app_administrationPageDef"); DCIteratorBinding docExtensionIter = dcBindings.findIteratorBinding("ExtensionsView1Iterator"); docExtensionIter.getViewObject().clearCache(); docExtensionIter.getViewObject().executeQuery(); Row newRow = docExtensionIter.getViewObject().createRow(); newRow.setAttribute("ExtensionId", newExtensionId); newRow.setAttribute("ExtensionName", fileExtension); docExtensionIter.getViewObject().insertRow(newRow); OperationBinding operationBinding = dcBindings.getOperationBinding("Commit"); Object result = operationBinding.execute(); return new Integer(newExtensionId.toString()); } /** * Test if an extension name exists in an iterator based on the extension Db table * @param extensionName, the extension name to look for * @return Boolean, True if the extension name is already existing in the database */ public Boolean extensionExist(String extensionName) { Boolean result = false; String testExtension = null; DCBindingContainer dcBindings = (DCBindingContainer)ADFUtils.findBindingContainer(getBindings(), "app_administrationPageDef"); DCIteratorBinding docExtensionIter = dcBindings.findIteratorBinding("ExtensionsView1Iterator"); ViewObject docExtensionVO = docExtensionIter.getViewObject(); docExtensionVO.clearCache(); docExtensionVO.executeQuery(); if (docExtensionVO.getEstimatedRowCount() != 0) { testExtension = docExtensionVO.first().getAttribute("ExtensionName").toString(); if (testExtension.matches(extensionName)) { result = true; } if (docExtensionVO.getEstimatedRowCount() > 1) { for (Integer i = 1; i < docExtensionVO.getEstimatedRowCount(); i++) { testExtension = docExtensionVO.next().getAttribute("ExtensionName").toString(); if (testExtension.matches(extensionName)) { result = true; }}} } return result; }

/** * Find the extension ID corresponding to the given extension name * @param extensionName, the extension name to look for * @return Integer, the extension ID of interest */ public Integer findAnExtensionFromName(String extensionName) { Integer resultingExtensionId = 0; String testExtension = null; DCBindingContainer dcBindings = (DCBindingContainer)ADFUtils.findBindingContainer(getBindings(), "app_administrationPageDef"); DCIteratorBinding docExtensionIter = dcBindings.findIteratorBinding("ExtensionsView1Iterator"); ViewObject docExtensionVO = docExtensionIter.getViewObject(); docExtensionVO.clearCache(); docExtensionVO.executeQuery(); if (extensionExist(extensionName.toLowerCase())) { if (docExtensionVO.getEstimatedRowCount() != 0) { testExtension = docExtensionVO.first().getAttribute("ExtensionName").toString().toLowerCase(); if (testExtension.matches(extensionName)) { resultingExtensionId = new Integer(0).valueOf(docExtensionVO.getCurrentRow().getAttribute("ExtensionId").toString ().toLowerCase()); } } if (docExtensionVO.getEstimatedRowCount() > 1) { for (Integer i = 1; i < docExtensionVO.getEstimatedRowCount(); i++) { testExtension = docExtensionVO.next().getAttribute("ExtensionName").toString().toLowerCase(); if (testExtension.matches(extensionName)) { resultingExtensionId = new Integer(0).valueOf(docExtensionVO.getCurrentRow().getAttribute("ExtensionId").toString ().toLowerCase()); } } } } return resultingExtensionId; }

Finally it misses only the functions creating the BLOB with its details and the function which will be called from the interface:

public Integer createTheDocumentBlob(BlobDomain file) { DBSequence newBlobId = new DBSequence("DOC_SEQ", ADFUtils.getApplicationModule("MedLibModule")); DCIteratorBinding docBlobIter = ((DCBindingContainer)getBindings()).findIteratorBinding("DocsView1Iterator"); ViewObject docBlob = docBlobIter.getViewObject(); Row newRow = docBlob.createRow(); newRow.setAttribute("DocId", newBlobId); newRow.setAttribute("DocBlob", file); docBlob.insertRow(newRow); OperationBinding operationBinding = getBindings().getOperationBinding("Commit"); Object result = operationBinding.execute(); return new Integer(newBlobId.toString()); } public void createTheDocumentDetails(Integer docBlob) { DCIteratorBinding docDetailsIter = ((DCBindingContainer)getBindings()).findIteratorBinding("AllFilesAndDetails1Iterator"); ViewObject allFilesAndDetails = docDetailsIter.getViewObject(); Row newRow = allFilesAndDetails.createRow(); newRow.setAttribute("DetailId", -1); newRow.setAttribute("DetailName", findExactName(uploadedFile.getFilename())); Integer docExtension = 0; if (extensionExist(this.getExtensionFromFileName(uploadedFile.getFilename()))) { docExtension = this.findAnExtensionFromName(this.getExtensionFromFileName(uploadedFile.getFilena me())); } else { docExtension = this.createAnExtension(this.getExtensionFromFileName(uploadedFile.getFilename())); } newRow.setAttribute("DetailExtension", docExtension); newRow.setAttribute("DetailType", findTheSelectedTypeFromList4UploadingNewFile()); newRow.setAttribute("DetailDoc", docBlob); java.sql.Date docDate = new java.sql.Date(new Date().getTime()); newRow.setAttribute("DetailDate", new oracle.jbo.domain.Date(docDate)); allFilesAndDetails.insertRow(newRow); OperationBinding operationBinding = getBindings().getOperationBinding("Commit"); Object result = operationBinding.execute(); }

public String uploadAction() { try { file = FileOperations.writeToBlobDomain(uploadedFile); Integer docBlob = createTheDocumentBlob(file); createTheDocumentDetails(docBlob); uploadedFile.dispose(); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } return librarySwitchDisplay(); } public void onUploading(ValueChangeEvent evt) { uploadedFile = (UploadedFile)evt.getNewValue(); fileName = uploadedFile.getFilename(); }

=> Adding controllers for downloading files:


To download a file, users will select it belong the existing ones then they will have to confirm the download on the confirmation page. In order to get the selected file and to display its name on the confirmation page, add the following attribute:
private CoreOutputText nameOfSelectedFile4Download;

Generate the corresponding accessors. The code editor has imported the following class:
import oracle.adf.view.faces.component.core.output.CoreOutputText;

Now add the function called when selecting a file:


public String selectFileToDownload() { DCIteratorBinding allFilesIter = ADFUtils.getIterator("AllFilesAndDetails1"); Row r = allFilesIter.getCurrentRow(); String selectedFileName = r.getAttribute("DetailName").toString(); selectedFileName = "You have selected " + selectedFileName + ", please confirm this is the file you want to download"; this.getNameOfSelectedFile4Download().setValue(selectedFileName); return libraryDownloadSwitchDisplay(); }

And finally add the function enabling to download the file:

public String downloadAction() { DCIteratorBinding blobIter = ADFUtils.getIterator("AllFilesAndDetails1"); Row r = blobIter.getCurrentRow(); BlobDomain file = (BlobDomain)r.getAttribute("DocBlob"); String fileName = (String)r.getAttribute("DetailName"); String fileExtension = (String)r.getAttribute("ExtensionName"); String fileMimeType = (String)r.getAttribute("ExtensionMimetype"); FileOperations.downloadFile(fileName, fileExtension, fileMimeType, file); //ADFUtils.executeOperation("app_LibraryPageDef", "Execute"); return libraryDownloadSwitchDisplay(); }

III. Designing the interfaces


a. Generating the administration page
The administrator of the application will use this page to manage the content of the type list proposed to the user. Actually each user will have to select a type in this list to classify the file he is uploading. This page will enable too to add or remove some of the allowed extensions and to change if needed the mime-type associated to the existing extensions.

i. Management of the type list


=> Building the table:
Open the Adiministration.jspx page from the Application Navigator, and the Structure Navigator, the Component Palette and the Data Control Palette from the Jdev menu. From the Data Control Palette: Find the TypesView1, drag and drop it on the first panel group Select Table and ADF Table. In the wizard, delete the field TypeId and check the Enable sorting and the Enable selection boxes.

=> Adding the specific functionalities:


The table will display the possible document types. The administrator will need to be able to save the changes brought to these types, but too to add and to delete them if needed. From the Data Control Palette: Expand the TypesView1 collection to find the proposed actions. From the Operations folder, drag and drop the Execute action on the Submit button located in the table. Choose Bind existing CommandButton. Now, repeat this step with the Delete action and with choosing ADF Command Button.

The Structure window should look like the following:

Under the Table facets are present different facets. The Selection facet, into which have been dropped the two buttons, From the Data Control Palette: From the Operations folder, drag and drop the Create action on the actions facet. Choose ADF Command Button. Right click on the new command button and choose Edit Command Button. In the Select an action drop down list, select Create insert.

=> Running the page:


The Administration.jspx page should look like the following:

Its possible to run the page by a right click on the page then select Run. The actions delete and create can be used, but there is no way for saving the data until now. Actually these actions enable to modify the collection build from the content of the database and the Execute action will submit the changes to the database, but the transactions have to be committed to the database to be saved permanently.

=> Adding the common functionalities:


From the Data Control Palette: Collapse the TypesView1 collection and find the Operations folder located under the node MedLibModuleDataControl. Drag and drop the Commit and the Rollback actions on the MenuBar into the page with choosing ADF Command Button. From the Component Palette: Drag and drop the Command Button component on the MenuBar into the page This button will enable to switch the administration panels between the tables for the type and for the extension management

ii. Management of the extensions and the mime-types


=> Building the table:
From the Data Control Palette: Find the ExtensionsView1, drag and drop it on the second panel group Select Table and ADF Table. In the wizard, delete the field ExtensionId and check the Enable sorting and the Enable selection boxes.

=> Adding the specific functionalities:


The table will display the possible document extensions and their associated mimetypes. The administrator will need to be able to save the changes brought to these details, but too to add and to delete them if needed. NOTE: More information about MIME: http://en.wikipedia.org/wiki/MIME From the Data Control Palette: Expand the ExtensionsView1 collection to find the proposed actions. From the Operations folder, drag and drop the Execute action on the Submit button located in the table. Choose Bind existing CommandButton. Now, repeat this step with the Delete action and with choosing ADF Command Button. From the Operations folder, drag and drop the Create action on the actions facet. Choose ADF Command Button. Right click on the new command button and choose Edit Command Button. In the Select an action drop down list, select Create insert.

=> Running the page:


The Administration.jspx page should now look like the following:

Its possible to run the page by a right click on the page then select Run. When using one of the Execute, Delete or Create actions, the Commit and Rollback buttons become available. These buttons enable to confirm or to declare null the changes.

b. Generating the library page


The library page will be used by users for uploading and downloading files.

i. Displaying the files


=> Building the table:
Open the Library.jspx page from the Application Navigator In the DataModel, the model layer has already been built in order to make easy the creation of the page displaying the different files. Like for the administration page, the principal table will be obtained from drag and dropping a collection. From the Component Palette: Drag and drop two PanelHeader components into the first panel group. Using the Property inspector, change the Text property of the two components, respectively by Select the file to download and by Confirm the download. Drop a PanelBox into the second PanelHeader, add in this panel box an OutputText and a PanelButtonBar with two CommandButton inside. From the Data Control Palette: Find the AllFilesAndDetails1, drag and drop it on the first PanelHeader. Select Table and ADF Table. Make the wizard matching the following screen shot:

=> Adding the specific functionalities:


The table will display all the files and users will need to be able to download the selected one and to upload new one. From the Data Control Palette: Expand the AllFilesAndDetails1 collection to find the proposed actions. From the Operations folder, drag and drop the Delete action on the Submit button located in the table. Choose Bind existing CommandButton. From the Component Palette: Drag and drop a Command Button component on the new Delete button with choosing ADF Command Button. It will be used for downloading the selected entry. Drag and drop a second Command Button component on the MenuBar into the page. It will enable user to switch to the upload panel.

ii. Enabling to upload new files


=> Building the global layout:
From the Component Palette: Drag and drop two PanelBox components into the second panel group, then drop one PanelHorizontal in the first box and two in the second. Into the first PanelHorizontal, drop an OutputText component, and in the Property inspector window, type Select a type into which classify your file in the Value property. Into the first PanelHorizontal of the second panel box, drop an InputFile component and change its Label property into Select the file to upload. Finally, in the second PanelHorizontal of this panel box, drop a PanelButtonBar, then add into it two Command Button components From the Data Control Palette: Drag and drop the TypesView1 collection into the first PanelBox in the second PanelGroup of the page. Select Table and ADF Table. Make the wizard matching the following screen shot:

In the Structure window, the page should now look like the following:

c. Binding the controllers and refining the display


Its now time for binding the interfaces with their controllers and to associate the corresponding labels in order to finalize the application

i. On the administration.jspx page


=> Binding the actions:
Only one action is needed on this page, the one which will enable to switch from the types management form and the extension management form Using the Structure and the Property Inspector windows: Find and select the first PanelGroup In the Property inspector, enter AdministrationTypePanel in the Id field Click in the Binding field then on the little button with the three dots. A wizard appears which enables to associate the panel group component with a bean. Select LibraryBean in the first list and administrationTypesPanelGroup in the second. The field should take the value: #{LibraryBean.administrationTypesPanelGroup}.

Repeat these operations for the second panel group: Find and select the second PanelGroup In the Property inspector, enter AdministrationExtensionPanel in the Id field Click in the Binding field then on the little button with the three dots. A wizard, enabling to associate the panel group component with a bean, appears. Select LibraryBean in the first list and administrationExtensionsPanelGroup in the second. The field should take the value: #{LibraryBean.administrationExtensionsPanelGroup}. Now add the function under the command button: Expand the menuBar and select the commandButton 1 In the Property inspector, click on the Action property then on the little button with the three dots. A wizard appears to associate a button to an action declared in a bean. Select LibraryBean in the first list and administrationSwitchDisplay in the second. The field should take the value: #{LibraryBean.administrationSwitchDisplay}.

=> Refining the display:


Some labels have been built automatically and also need to be changed in order to be more understandable. The only label which really needs to be changed on this page is the one displayed on the command button commandButton 1. This button has to display Go to Extension Management or Go to Types Management depending on which table is displayed in the page. To carry out this complex display the best way is to use the Expression Language. NOTE: More information about the Unified http://en.wikipedia.org/wiki/Unified_Expression_Language Expression Language:

Using the Structure and the Property Inspector windows: Find and select the command button commandButton 1 In the Property inspector, click on the Text property then on the little button with the three dots. A wizard appears to build the button label. Expand JSF Managed Beans > LibraryBean > administrationTypesPanelGroup and double click on the rendered attribute. Finally modify the proposed expression to obtain the following:
#{LibraryBean.administrationTypesPanelGroup.rendered? 'Go to Extensions Management':'Go to Types Management'}

Do the same for the three buttons on the extension table: Find and select the command button Create1and rename it in the property inspector with Create. Find Execute1 and Delete1, then change them for Execute and Delete.

Finally, make the document extensions management panel disappearing: Select the second PanelGroup. From the Properties Inspector, find the attribute Rendered and set it to false.

ii. On the Library.jspx page


=> Adding some needed binding:
To enable the upload of new file, the page needs to be associated to the VO controlling the access to the table Docs which contains the BLOBs: Right click on the Library.jspx page and select Go to Page Definition. In the Structure Inspector, find the executables folder, right click on it and select Insert inside executables > iterator. From the wizard, select the DocsView1 and accept. Now, in the Structure Inspector, find the bindings folder, right click on it and select Insert inside executables > table. In the Select an Iterator drop down list, find DocsView1 then assume the two attributes are in the right panel called Display Attributes. To confirm the changes made into the database, its needed to commit them. This action will be called from the bean but need to exist in the bindings: Now, in the Structure Inspector, find the bindings folder, right click on it and select Insert inside executables > action. In the Data Collection panel, click on the MedLibDataControl item and in the Select an action list choose Commit (with a French version the label is Valider, in this case accept in then in the action id change it for Commit)

=> Binding the actions:


To be able to upload files from the Library page, the Form which contains all the component has to be change from the current which is a JSF one to an ADF one. Open the Library page if needed, and click on the Sources tab. Find the tags <h:form> and </h:form> and change them for <af:form> and </af:form>. Return on the Design facet and select the af:form in the Structure window. Find the attribute UsesUpload in the Properties Inspector and set it to true. Five different actions are needed on this page: uploading and downloading files, and the three actions enabling to switch the display between the two panel groups and between the two panel boxes and the two panel headers inside of each pane l group.

Using the Structure and the Property Inspector windows: Find and select the first PanelGroup In the Property inspector, enter LibraryDownloadPanelGroup in the Id field Click in the Binding field then on the little button with the three dots. A wizard, enabling to associate the panel group component with a bean, appears. Select LibraryBean in the first list and libraryDownloadPanelGroup in the second. The field should take the value: #{LibraryBean.libraryDownloadPanelGroup}. Repeat these steps with the second PanelGroup. Use LibraryUploadPanelGroup in the Id field and complete the Binding to obtain #{LibraryBean.libraryUploadPanelGroup}. Expand the first PanelGroup, and select the first PanelHeader. Set the properties Id and Binding to LibraryDownloadSelectionPanelHeader and #{LibraryBean.libraryDownloadSelectionPanelHeader}. Select the second PanelHeader and set Id and Binding to LibraryDownloadConfirmationPanelHeader and #{LibraryBean.libraryDownloadConfirmationPanelHeader}. Expand the second PanelGroup, and select the first PanelBox. Set the properties Id and Binding to LibraryUploadTypeSelectionPanelbox and #{LibraryBean.LibraryUploadTypeSelectionPanelbox}. Select the second PanelBox and set Id and Binding to LibraryUploadFileSelectionPanelbox and #{LibraryBean.LibraryUploadFileSelectionPanelbox}. Now add the functions under the command buttons: Expand the menuBar and select the commandButton 2 In the Property inspector, click on the Action property then on the little button with the three dots. A wizard appears to associate a button to an action declared in a bean. Select LibraryBean in the first list and librarySwitchDisplay in the second. The field should take the value: #{LibraryBean. librarySwitchDisplay}. Repeat these steps to trigger the actions libraryDownloadSwitchDisplay and libraryUploadSwtichDisplay with respectively the command buttons commandButton 5 and commandButton 3 Do it again for have the actions #{LibraryBean.downloadAction}, #{LibraryBean.uploadAction}, #{LibraryBean.selectFileToDownload} and #{LibraryBean.libraryUploadSwtichDisplay} respectively on the buttons commandButton 6, commandButton 4, commandButton 1 and Submit.

The outputText component which will display the name of the selected file to download needs to be linked to the bean: Find the outputText1 from the Structure window. In the Property inspector, enter NameOfSelectedFile4Download in the attribute id. In the binding attribute select LibraryBean and nameOfSelectedFile4Download to obtain the value #{LibraryBean.nameOfSelectedFile4Download}. The last action to bind is the one which enables to automatically keeping up-to-date the UploadedFile attribute in the bean with the selected file: Find the af:InputFile from the Structure window. In the Properties Inspector, find the ValueChangeListener attribute and set its value to #{LibraryBean.onUploading}.

=> Refining the display:


Now its time for changing the label of the different buttons. Using the Structure and the Property Inspector windows, change the Text attribute of the buttons according to those proposed in the following table:

Button current label


commandButton 1 commandButton 2 commandButton 3 commandButton 4 commandButton 5 commandButton 6 Submit

Button wanted label


Download this file #{LibraryBean.libraryDownloadPanelGroup.rendered? 'Upload new File':'Download a File'} Cancel upload Confirm upload Cancel download Confirm download Select this type

Finally, your application is almost ready to use. The last step is to avoid the display of some panels at the first use of the application. The Rendered attribute has to bet set to false for the second PanelBox of the second PanelGroup, the second PanelGroup and the second panelHeader of the first PanelGroup.

You can now run your application. To access from one page to the other change in the internet browser address field Library.jspx by administration.jspx or administration.jspx by Library.jspx depending on the current displayed page. Lot of improvements can be added but that will be the subject for next tutorials.

Vous aimerez peut-être aussi