Hi all
is this possible and how ?
We'd like to give the end users a (possibly) permanent URL where they could retrieve the report output (which could be stored in Aris Connect Document Repository)
Thanks
PS : a javascript solution is OK as our report is not a wysiwyg report
Hi Robert
OK, let's assume I know how to get the report ouput content in my report
Looking at https://your_aris_server_/abs/help/en/script/ba/index.htm#report_OBJECTS_ADSReportComponent.htm
One could go along the following lines :
var stream = (scheduled report output content, don t know yet how to get it)
var ads = Context.getComponent("ADS")
var repository = ads.getADSRepository ( "MyRepositoryFolder")
var doc = repository.getDocument("Myreportoutput.xls")
if (doc==null) // doc does not exist
{
var metaInfo = repository.createDocumentMetaInfo("DocTitle","filename","Description");
doc = repository.createDocument(parentFolder,metaInfo,stream);
}
else //doc exists , create new wersion
{
repository.updateDocumentContent(doc,doc.getDocumentMetaInfo(), stream,"Update")
}
Well, there could be two ways:
1) directly when running the script
var oFile = Context.getFile(Context.getSelectedFile(), Constants.LOCATION_OUTPUT);
var oByteArrayInputStream = new java.io.ByteArrayInputStream(oFile);
var oInputStream = new java.io.BufferedInputStream(oByteArrayInputStream);
2) by usage of an second script that uses the report scheduler
var reportScheduler = Context.getComponent("ReportScheduler");
var aByteArrayResult =
reportScheduler.getDecryptedScheduleResult("scheduledReportGUID", "username", "password", false);
var aSelectedFile =
reportScheduler.getZipEntries(aByteArrayResult);
var aByteArrayXLSX = null;
for (var i in aSelectedFile) {
if (aSelectedFile[i].getName().equals("OutputFile.xlsx")) {
aByteArrayXLSX = aSelectedFile[i].getData();
break;
}
}
var outputFile = new java.io.File(filePath + "\\OutputFile.xlsx");
var fop = new java.io.FileOutputStream(outputFile);
if (!outputFile.exists()) {
outputFile.createNewFile();
}
fop.write(aByteArrayXLSX);
fop.flush();
fop.close();
Not quite sure if the second one works, but the first one should be usable anyway...
Robert
I guess I'll have to write two scheduled reports
- the first one to create the document I want to share with end users (and which will be stored encrypted somewhere on the aris server, not avaialble to end users)
- the second one who will retrieve that document and store it in Aris Document Storage, available to Aris connect end users
Why though? If you want to store something in the ARIS Document Storage, just store it in the ARIS Document storage.
I've written about this topic in this thread https://www.ariscommunity.com/users/nishabaste/2021-05-18-using-ads-through-aris-scripting#comment-27914 explaining how to retrieve and update ARIS Document Storage documents by report.
It boils down to
1. Write output file as if you'd want to send it to a client
2. Locate ADS Document with ADS Report Component Interface
3. Get output file as byte array with Context.getFile(...)
4. Create Java ByteArrayInputStream with byte array
5.give ByteArrayInputStream to ADS method which will use it to update the document
6. If you want to make sure nobody can use your report to get the file directly, wipe it from the output directory with Context.deleteFile(...)
Hello Michel,
Today I was hitting the same issue of uploading report output directly to ADS, not willing to have an intermediate step where the output is stored in a file on the server.
I succeeded in doing this and am happy to share with the ARIS Community. Fair to say is that I've been inspired by the file ADSUploader.js which can be found in the 'Reports/Dashboard data' folder. The folder structure (Dashboarding/<database name>/) is inspired by the ADSUploader.js. You can change this and all hard-coded variables to your needs.
All required code is inside the function. One can copy/paste the function into ones code and then call it like shown in the first code snippet.
var xmlOutput = Context.createXMLOutputObject("Models.xml", "Models");
// assemble your XML document...
uploadXmlOutputToAds(xmlOutput, "DHAN", "Models.xml", "All models as xml", "All models as xml description.");
The upload function:
// Upload an in-memory XML document directly to ADS.
// params:
// outputObject : XML outputObject.
// adsFolderName : Last part of the folder name in ADS where the document is stored.
// Complete foldername: /Dashboarding/<database name>/<adsFolderName>
// adsFileName : Name of the file in ADS. Include extension.
// documentTitle : Title of the document as shown in ADS metadata.
// documentDescription : Description of the document as shown in ADS metadata. Optional.
//
// When the folder in ADS doesn't exist, it will be created.
function uploadXmlOutputToAds(outputObject, adsFolderName, adsFileName, documentTitle, documentDescription) {
var ads = Context.getComponent("ADS");
var db = ArisData.getActiveDatabase().Name(Context.getSelectedLanguage());
var repository = ads.getADSRepository("portal");
var rootFolder = repository.getRootFolder();
var folderName = "Dashboarding\\" + db + "\\" + adsFolderName;
var adsFolder = repository.getFolder(rootFolder, folderName);
if (!adsFolder) {
adsFodler = repository.createFolder(rootFolder, folderName);
}
var documentInfo = repository.createDocumentMetaInfo(documentTitle, adsFileName, documentDescription);
var outputByteArray = outputObject.getDocumentContent();
var document = repository.createAndOverwriteExistingDocument(
adsFolder, documentInfo,
new java.io.ByteArrayInputStream(outputByteArray) )
}
A screenshot of the result in ADS is attached.
Best regards,
Harm
Ok ,thanks to Robert and Kay I managed to :
- execute the report , either by hand or by scheduling it
- send the report output file to the ADS (updating the existing document if it already exists or creating it if not)
For those interested , the working code is just below.
However there is still something that bugs me.
The script works like this :
- The report creates its output and writes it (to the desktop client if executed manually , or on the server I guess if scheduled) . This is done when calling writeReport()
- The reports then reads back the file, turns it into a stream, then sends the stream to the ADS which creates a new file
First question is : how to delete the unused file (the one created in setp one above) ?
Second question : how to avoid altogetther the creation of this temporary file ? Is there a function of the OutputObject that could be called to get the byte stream needed by the ADS functions ?
Thanks
Working code snipet :
oOutput.WriteReport() // report output is written to a file
// retrieve the file content
var oFile = Context.getFile(Context.getSelectedFile(), Constants.LOCATION_OUTPUT);
var oByteArrayInputStream = new java.io.ByteArrayInputStream(oFile);
var oInputStream = new java.io.BufferedInputStream(oByteArrayInputStream);
// connect to the ADS
var ads = Context.getComponent("ADS")
var repository = ads.getADSRepository ( "portal") // has to be portal according to Aris documentation
var parentFolder = repository.getFolder("MyDirectory/MySubDirectory"); // whare I want to put the report output
var doc = repository.getDocument(parentFolder,null,Context.getSelectedFile())
if (doc==null) // doc does not exist
{
var metaInfo = repository.createDocumentMetaInfo("DocTitle","myoutput.xlsx","Description");
doc = repository.createDocument(parentFolder,metaInfo,oInputStream);
}
else //doc exists , create new wersion
{
repository.updateDocumentContent(doc,doc.getDocumentMetaInfo(), oInputStream,"Update")
}
The report creates its output and writes it (to the desktop client if executed manually , or on the server I guess if scheduled) . This is done when calling writeReport()
No, calling writeReport() writes a file whose content previously only existed in Server RAM to a temporary output directory (on the server) that is specifically created for an instance of your report execution. It does nothing more - no file is passed to the client while the report is running.
After your report concludes there are two conditions for a file to be transfered to the client:
- the file name must be registered as an output file (the selected file is registered by default, you may manually add more file names e.g. with Context.addOutputFileName(...))
- the file must actually exist (obviously not even the automatically registered selected file can be transfered if you never wrote such a file to the output directory, or if you wiped it from the output directory before the report concludes)
how to delete the unused file (the one created in setp one above) ?
The file created in step one can be deleted with
Context.deleteFile(Context.getSelectedFile(), Constants.LOCATION_OUTPUT);
In addition to deleting the file I also recommend that if you really don't want to transmit your file to any potential client you create your file with a different filename than the one provided by Context.getSelectedFile() (and adjust the first parameter of the Context.deleteFile(...) call). As I've written before, this file name is registered by default for output file transfer, therefore if you instead use something like "businessReport." + your file extension without registering this made up file name as an output file it would never be transfered to begin with. Also make sure to set the selected file with Context.setSelectedFile("noRealName.noRealExtension") to something that's not "businessReport." + your file extension. This prevents users from acquiring the file even if they were to manually set their output file name to "businessReport." + your file extension.
how to avoid altogetther the creation of this temporary file ? Is there a function of the OutputObject that could be called to get the byte stream needed by the ADS functions ?
That I don't know. The ARIS OutputObject is most likely backed by different libraries depending on the output format (e.g. Apache POI if you create a docx Document, ...) and I doubt there is a universal method to tell all those different libraries to output into a buffer instead of writing a file to the filesystem.
Thanks all @Robert Goldenblaum and @Kay Fischbach
For the record below a code snippet that achieves the desired result
var outputFilename ="test.txt"; var outputObject = Context.createOutputObject(Constants.OutputTXT,outputFilename); outputObject.OutputTxt(Context.getScriptInfo(Constants.SCRIPT_NAME)+"\n"); var docTitle = "Doc title"; // add more output outputObject.WriteReport() ; // save to ADS var ads = Context.getComponent("ADS") var repository = ads.getADSRepository ("PORTAL"); var parentFolder = repository.getFolder("My Folder"); var file = Context.getFile(outputFilename ,Constants.LOCATION_OUTPUT); var byteArrayInputStream = new java.io.ByteArrayInputStream(file); var inputStream = new java.io.BufferedInputStream(byteArrayInputStream); var metaInfo = repository.createDocumentMetaInfo(docTitle,outputFilename ,"My description"); repository.createAndOverwriteExistingDocument (parentFolder, metaInfo, inputStream ); // or if one wants to add versions instead of overwriting /* var doc = repository.getDocument(parentFolder,docTitle,outputFilename); if (doc==null) // doc does not exist { doc = repository.createDocument(parentFolder,metaInfo,inputStream); } else //doc exists , create new wersion { metaInfo = doc.getDocumentMetaInfo(); repository.updateDocumentContent(doc,metaInfo,inputStream,"Update") } */