This section describes, in a single place, the collection of user custom exits which facilitate the handling of cloud-resident attachments, image field values, and document field values.
The basic requirement described in this section is to make cloud-based or repository-based files behave like uploaded file objects in ExtraView. Generally, ExtraView stores upload objects in the file system or the database; some user custom exits permit storage of upload objects in user-defined external storage.
User custom exits support cloud-based file systems due to the wide variety of cloud storage types and the assumptions of the current upload process. No two cloud-based systems have the same interface.
Each of these operations requires specific processing by user custom exits when the upload object is in the cloud or a non-ExtraView repository. The user custom exits defined in this section are the only ones used for cloud/repository upload objects. There are other, specific exits that deal directly with file Attachments, for example, ucDeleteAttachment, but these should not be used since they may or may not be invoked for cloud/repository upload objects. The only legacy interfaces used for these upload types are ucViewAttachment and ucViewDocument. The upload process consists of the following high-level, user-initiated, operations:
A user custom exit is made available to populate an HTML DIV on the upload page with HTML created within the user custom exit. The DIV will become visible based on the MODE of the upload screen. This is selectable by the user from one of three modes: Drag and Drop, Standard and Repository. All messages and button titles visible by the user are customizable.
The user custom exit modifies a tags HashMap that is used with the inbuilt addAttachment.html template to produce the upload page.
There are two mandatory tags of interest to the user custom callout:
Other tags of interest are:
The submit button used for standard mode form submission is in the tags HashMap with the key SUBMIT_BUTTON. This can be reused for inclusion in the repository html.
The parameter uploadObjectType is either ATTACHMENT, IMAGE or DOCUMENT.
Interface:
public void ucUploadSetForm ( HashMap tags, SesameSession session, Connection dbconn, String uploadObjectType ) throws Exception ;
While it is possible for the repository DIV to generate a form submission that bypasses all existing base ExtraView code, there would be substantial work involved in the new user custom service that simply replicated existing code. Therefore, it is strongly recommended that the upload HTML designer use the existing action/option and HTML FORM for submission to the server.
A user custom exit is made available to process the form parameters and request object received from the upload page. This user custom exit is responsible for:
This custom exit is not responsible for:
Once the user has entered the necessary information to the upload screen, the form is submitted as a multipart form, and the ExtraView base code parses the request. The result consists of form parameters in a HashMap, representing the values entered, or pre-seeded on the upload page. If the page is submitted in the Repository mode, the form parameters and the request are passed to the user custom exit ucUploadProcessForm defined here. A new, partially constructed uploadObject is passed as a parameter. This will be either an Attachment, a DocumentItemUDF, or an ImageItemUDF object that can be used in creating the upload object in the database. In this object the required fields that are populated are: ITEM_ID, UDF_ID (if any), CREATED_BY_USER and UPDATED_BY_USER. Other system-generated fields such as LAST_DATE_UPDATED are populated during transactions on the upload object. Aside from the pre-populated fields and the system-generated fields, the user custom exit is responsible for setting the object values using its setter methods.
The form parameters here do not support multi-valued parameters. This is a legacy-based restriction due to the way the parameters are handled internally in ExtraView. If multiple values are needed for a specific parameter, it is recommended that the parameter name be uniquefied with numbers, e.g., file1, file2, file3, …. in order to work around this restriction.
The string returned by this method is an error message that will alert the user in the upload screen; null for successful upload.
Interface:
public String ucUploadProcessForm ( HashMap formParameters, SesameSession session, Connection dbconn, String uploadObjectType, Object uploadObject ) throws Exception ;
There are special considerations for the ADD screen because the ITEM_ID is 0 as the issue has yet to be added to the database and assigned its ITEM_ID. For image and document data types, when the ITEM_ID is 0, the executeTransactionUncommitted should be used to store the imageItemUDF; otherwise, use the executeTransaction method.
For attachments, when the ITEM_ID is 0, the attachment is stored in an attachment list in the current session. When the issue is later committed to the database, the proper fields will be filled in and the attachment will be stored in the database.
Two user custom exits are available to view the upload object in the browser according to its MIME type. This stage also includes the rendering of a thumbnail image of the object.
There are two methods for rendering an upload object from a repository:
Interface:
public boolean ucViewDocument (OutputStream out, ImageItemUDF iiu) ; public boolean ucViewAttachment (OutputStream out, Attachment attachment);
For attachments, some parts of the object metadata are editable, e.g. the file description. There is a user custom exit for validation/modification of the edited metadata for cloud/repository upload objects.
User modification of upload objects is restricted to the file description, also known as ALT_TEXT, and the charset encoding. A user custom exit is provided to process the modifications before they are made to the object. This exit may validate the parameters, produce an error message, or allow the transaction to proceed.
Interface:
public String ucUploadEditObject ( HashMap formParameters, SesameSession session, Connection dbconn, String uploadObjectType, Object uploadObject ) throws Exception ;
All upload objects may be deleted based on actions by the user, e.g. the deletion of containing issue. There is a user custom exit for cloud/repository object deletion to permit recycling of resources owned by the upload object.
public String ucUploadDeleteObject ( SesameSession session, Connection dbconn, String uploadObjectType, Object uploadObject ) throws Exception ;
The user custom exit ucDeleteAttachment is not invoked with cloud upload objects.
The string returned by these methods is an error message that will alert the user in the edit/delete screen; null for successful transaction.
When an upload object is contained in an issue that is being cloned, and the upload object is a cloud/repository-based object, a user custom method can be invoked to populate a cloned object. At a minimum, any thumbnails should be copied, and other repository operations may be needed.
In the clone operation on the edit screen, contained upload objects must be replicated into the new issue. In the interface, the newUploadObject is the partially populated new upload object (Attachment, ImageItemUDF, or DocumentItemUDF) that can be used to perform the transaction to store it in the database.
Interface:
public String ucUploadClone ( Object uploadObject, SesameSession session, Connection dbconn, String uploadObjectType, Object newUploadObject ) throws Exception ;
Thumbnail images are considered to be contained in the upload object; therefore, they must not be shared between objects, and in a clone operation, the thumbnail must be created as a new object in the database.
After the completion of an upload operation, there may be resources that were allocated during the upload that need to be recycled. The Finish Upload operation permits cleanup, as it is the last operation performed after the upload is complete.
Interface:
public String ucUploadFinish ( Object uploadObject, SesameSession session, Connection dbconn, String uploadObjectType ) throws Exception ;
The String return value is an error message or null if successful.
The binary content of the uploaded object must be made available for email inclusion. Emails that include attachments, images, or documents generally have a thumbnail of the object in addition to the binary object in its entirety, not just a link. The ucUploadGetContent method is invoked to populate the email message with the content of the object. The thumbnail is obtained directly from the object in the database.
Interface:
public InputStream ucUploadGetContent ( Object uploadObject, SesameSession session, Connection dbconn, String uploadObjectType ) throws Exception ;
The InputStream returned value must stream the binary contents of the upload object for inclusion in emails.
The metadata associated with document or image field object consists of the following (those preceded by “*” are values that should be defined by user custom code):
The metadata associated with an attachment object consists of the following (those preceded by “*” are values that should be defined by user custom code):
QuickFind is not capable of building indexes based on the contents of cloud/repository objects. A future release will cover this functionality.
This is a Java source code example of how to create a thumbnail and store it into an ImageItemUDF object in the database. In this example, the image file is assumed to be readable (iiu.getTempFile()).
int maxPixelsPerDimension = 4000; String appDefaultMax = ApplicationDefault.getAttribute("MAX_IMAGE_DIMENSION_PIXELS"); if (isANumber(appDefaultMax)) { maxPixelsPerDimension = Integer.parseInt(appDefaultMax); } // check against max dimensions... int[] dimensions = ImageProcess.getDimensions( iiu.getTempFile(), ""); if (dimensions[0] > maxPixelsPerDimension || dimensions[1] > maxPixelsPerDimension) throw new Exception(Z.m.msg(session, "Image too large")); // make the thumbnail... thumbFile = File.createTempFile("thumb", iiu.getFileName(), new File(Z.getTempDir())); status = (new ImageProcess()).makeThumbnail(iiu.getTempFile(), thumbFile, iiu.getFileName()); if (status) { iiu.setThumbnailSize( (int) thumbFile.length()); thumbIs = new FileInputStream(thumbFile); iiu.setThumbnailBlobIS(thumbIs); is = new FileInputStream(iiu.getTempFile()); iiu.setValueBlobIS(is); String userId = session.getUserId(); iiu.executeTransactionUncommitted(userId); is.close(); is = null; // If we got here with no exceptions commit and return; dbconn.commit(); status = true; } else throw new Exception(Z.m.msg(session, "The most probable reason is that it is not an image file."));
Thumbnails for Attachments are separate Attachment objects with a type_id = 1. To create a thumbnail, the following example may be used:
public boolean generateThumbnail(Attachment orig, Connection dbConn) { boolean status = false; String origFilename = orig.getFileName(); String outFilename = null; File strtsFile = orig.getTempFile(); String strtsFilename = orig.getOrigFileName(); if (origFilename != null) outFilename = origFilename.substring(0,origFilename.lastIndexOf(".")) + "_thm" + origFilename.substring(origFilename.lastIndexOf(".")); File thumbnailFile = new File(strtsFile.getParent(),outFilename); String test = thumbnailFile.getAbsolutePath(); if (ImageProcess.canMakeThumbnail(origFilename)){ try { DbTime dbt = new DbTime(dbConn); ImageProcess ip = new ImageProcess(); status = ip.makeThumbnail(strtsFile,thumbnailFile,origFilename); this.tempFile = thumbnailFile; if (this.tempFile != null) this.tempFilePath = thumbnailFile.getAbsolutePath(); this.origFileName = outFilename; this.fileName = outFilename; this.fileSize = thumbnailFile.length(); this.problemId = orig.getProblemId(); this.dateCreated = dbt.getDbNowTimestamp(); if (!status) { this.errorMsg = Z.m.msg(session, "Cannot generate thumbnail. The file is not the right type."); } } catch (Exception e) { //ErrorWriter.write(e, ErrorWriter.LOGERR); status = false; } } // Log the failure here, success will be logged later return status; }