Hi there AppWorks fans,
Welcome to a new installment of AppWorks tips.
This time we dive into the content of Appworks; And not just content…No, content uploaded from our end-users via the ‘Contents’ and ‘File’ building blocks on our crafted entities.
It’s also a much-asked question from people around me, and I have also some questions myself to get an answer on:
- What is the server location?
- Is it secured and who has access?
- Is it encrypted (or can it be encrypted)?
- How is it linked to our entity?
What we leave out of scope are the document store connectors that make it possible to send content to another storage location like ‘Content server’, ‘Documentum’ or any other external location. We focus on pure on the default AppWorks storage in this post!
Let get right into it…
Let’s spin up our VM and dive into a project (for me a clean project) with our developer user ‘awdev’.
Create a basic entity called ‘case’ and with that all the basic building blocks, so you are able to create new instances in runtime…By now you should be familiar with that basic concepts of entity modeling…correct? And if you use version 20.3 of the platform you can even faster prototype an entity with the “Generate a default UI…” option on entity creation!
This is what I start off with as the entity:
In a project like this:
Nothing fancy…nothing special.
Next…
Adding a ‘File’ building block
Back in the ‘case’ entity hit the corresponding building block for this section…
When we have a look in the settings for the File building block on the right panel we see an interesting option:
So, we are able to save it on a self-defined location, but we just leave it empty. It will be saved somewhere in the ‘repository root’ wherever that might be!? We’ll double check on this one later on!
Next…
Adding a ‘Contents’ building block
Well, add the corresponding building block and double check the configuration panel on the right side…
And there we see it’s saved in a variable ‘${system.organization}’ location. Same for this one…I really have no idea where that might be!?…We’ll see…We just leave it with the default value!
Next…
Uploading content in Runtime
Well, it’s time for some publishing of our project to runtime, so we can create a new instance of our brand-new ‘case’ entity!
Ok, now open the ‘case’ where we directly see we miss something…
We have the ‘Upload’ button…That’s correct and makes it possible to upload content for our ‘File’ building block, but what about the ‘Contents’ building block?…Well, let’s fix that one first…
Back in design-time, open the ‘DefaultLayout’ that was generated for us to be able to ‘view’ the ‘case’ instances.
In this editor we need to add the ‘Contents’ panel to the layout.
When done…publish and refresh runtime!
Now we’re getting somewhere…An ‘Upload’ for the ‘File’ building block, and a ‘Plus-sign’ for the ‘Contents’ building block.
Well…where are you waiting for…upload, upload, upload!
First the ‘Upload’…
After OK, you will see something like this:
Ohw yeah…I forget to tell you!…Make sure you also add the ‘Preview’ panel to your layout! 😜
Next is the ‘Plus-sign’ for our ‘Contents’ BB…
And once it’s uploaded and marked for ‘viewing’ you will start to see something like this:
It’s nice to see that the ‘Preview’ panel shows both our uploaded content files in a ‘tabbed’ structure for you to switch…great!
Now we’ve uploaded content for both those building blocks it’s time to do a search on the server…
The search for content on the server side
find /opt -type f -cmin -5
Provides me with some information, but that’s not any of my content…or is it?
1 | /opt/tomee/apache-tomee-plus-8.0.3/logs/catalina.out |
That cxf-tmp-thingy is an interesting one…You need to be fast as it is cleaned up before you get the chance to grab a copy!
Apache CXF™: An Open-Source Services Framework
In my MobaXTerm tool I can see the file passing by, and we’re able to quickly download it…
Well…let’s give it the original extension (in my case a .png) and open the file…HaHa…You see…got ya! 💪
Okay…So something is going on in our server…as expected I would say!
What I also see on my server when I view a file are these calls in tail -f /opt/tomee/latest/logs/catalina.out
1 | com.opentext.docservice.rest.api.NodeService.getDocumentContentById GET/home/app/documentservices/rest/nodes/0800273b-f379-a1ea-bb70-ba48cf42bda4/content |
For the rest…nothing more…So where is our content saved?
Well, our next (and always helpful tool) is the CMC tooling…
CMC snorkeling
Start the tool with: sh /opt/opentext/AppWorksPlatform/defaultInst/bin/cmc.sh
Make sure you export the display to your local machine:
export DISPLAY=IP:0.0
Let us starts with the ‘Contents’ BB part…Remember the path: ${system.organization}/${solution.name}/${contentbuildingblock.path}
Well, open the ‘Repository Browser’, login (with in my case password ‘admin’) and connect to the ‘Cordys System’ database…
Browse to this location and see the result that matches our path!
Check also that right-top panel as you see an interesting ‘DocumentContent’ node…Would it be a Base64 string of our content?
Well…let’s find out!
Copy the string and paste it as new .txt file!
Go to https://www.base64decode.org/; make sure you are in ‘Decode’ mode; upload that .txt file; hit that decode button and download your content…Ohw mama…do we learn some nice stuff here! 😎
Now the content of our ‘File’ BB!
That would be this path: '{repository root}\{solution name}\{entity name}\{entity id}'
After searching in CMC…I really don’t have a clue!?
….
And after 10 min. (and a short coffee break) I get to the conclusion that my initial upload in runtime for the ‘File’ BB got a deletion as I was playing along…you stupid F%^$@%$!!
Here you have it…Off course exactly the same only a level higher in the tree with that same Base64 ‘DocumentContent’ node!
Database insertions
Let’s take it one step further and double check if the database also gets some kind of update!?
We have a PostgreSQL database up and running and to get track of the insert statements we need to change some setting in sudo vi /var/lib/pgsql/11/data/postgresql.conf
Update this setting: log_statement = 'all'
And restart the service: systemctl restart postgresql-11.service
Check the logging with: sudo tail -f /var/lib/pgsql/11/data/log/postgresql-{day}.log
We see 2 interesting queries pass by during the ‘File’ BB upload:
1 | insert into XDS_DOCUMENT (REVISION,STACK_LEVEL,DOCUMENT_ID,NAME,DESCRIPTION,CREATED_BY,LASTMODIFIED_BY,LASTMODIFIED_DATE,CREATED_DATE,TYPE_ID,TYPE_REVISION,PARENT_ID,CONTENT,QUALIFIED_NAME,OPTIMISTIC_LOCK,ACCESSCONTROLPOLICY_ID,INHERIT_PARENT_ACP,INTERNAL_NAME) values ('DocumentStore','2','0800273b-f379-a1ea-bbad-fb42f9eab05c','logo.png','logo.png','cn=SYSTEM,cn=organizational users,o=system,cn=cordys,cn=defaultInst,o=mydomain.com','cn=SYSTEM,cn=organizational users,o=system,cn=cordys,cn=defaultInst,o=mydomain.com','2020-09-04T14:07:11.162','2020-09-04T14:07:11.162','ID_TYPE_XMLDOCUMENT','_XDS_ROOT_BRANCH','0800273b-f379-a1ea-bb70-99b762a53da4','<content><MimeType>application/text</MimeType><LastModified>2009-04-29T12:13:00</LastModified><DocumentContent>Base64_String</DocumentContent><Properties/></content>','-- listing properties -- LastModified=2020-09-04T14:07:11 FileName=logo.png ItemId=0800273bf379a1eabb6f5a0113a0222b.1 MimeType=image/png','1','OPEN_TO_ALL_ACL','1','logo.png') |
Let’s have a nice UI look with HeidiSQL!
What we also see here are the tables for the ‘Contents’ BB!
SELECT * FROM o2appworkstipsappworkscasecontents;
Gives a result like this:
SELECT id, id1, s_content_type, s_filename, s_filesize, s_storage, s_lastmodified, s_title FROM o2appworkstipsappworkscontents;
Gives a result like this:
Wowsers!…Well, I don’t know how deep your snorkeling goes, but it looks to me like we reached the bottom of the lake here! What an experience and how nice to see how things stick together!
I give it a “DONE” for this post where we learned about data storage for the ‘Contents’ and ‘File’ building block. What we see is a save of the content as Base64 string in the XML storage that is available with our platform. In the database we see a storage pointer to that XML storage location! We learned a lot again about the content storage part of the platform, and it’s always great to see how things work behind the screens. Have a greatly earned week-end, and I see you in the next one…
Don’t forget to subscribe to get updates on the activities happening on this site. Have you noticed the quiz where you find out if you are also “The AppWorks guy”?