Thursday, February 21, 2013

View Outputformat "json" issue

I got problem with "Outputformat=json" for view. In the case of "!" sign presence in a view column, it wrapped to "\!". That is incorrect for canonical JSON.

I use JSON for HTML output, so I fix it by replacing "!" to it's HTML code "!".

To fix - place simple formula in to the column value:
@ReplaceSubstring(HTMLinList;"!";"!")


Friday, February 8, 2013

Dive in to ace

We use HTML templates in our project. Unfortunately there is no ability to good editing this templates in the IBM Notes client


I dig around a little and found a cool thing - ace - that help us a lot.
So, xPages, ace, jQuery  and few hours of work:



Monday, February 4, 2013

Light reader of www.alexa.com rank

Alexa is a good site to check you rank, unfortunately it's does not store statistic for the sites that have less than 100,000 rank.

You could buy account, for store such statistic for you own site.

Sometime you need to look for the statistic of your competitors, that are lower than 100,000.

I create a little program that allow you to gather statistic for any site that is on the www.alexa.com.

You need to put URL in to the properties file, run program and look in to the resulting json.

input example

url.1=http://www.alexa.com/siteinfo/championselect.net
url.2=http://www.alexa.com/siteinfo/elohell.net
url.3=http://www.alexa.com/siteinfo/lolcounter.com
url.4=http://www.alexa.com/siteinfo/lolcounterpicks.com
url.5=http://www.alexa.com/siteinfo/counterlol.org
url.6=http://www.alexa.com/siteinfo/picklol.net
url.7=http://www.alexa.com/siteinfo/counterpicker.com

result example

{
  "http://www.alexa.com/siteinfo/championselect.net" : "10,546",
  "http://www.alexa.com/siteinfo/elohell.net" : "16,323",
  "http://www.alexa.com/siteinfo/lolcounter.com" : "16,487",
  "http://www.alexa.com/siteinfo/lolcounterpicks.com" : "462,863",
  "http://www.alexa.com/siteinfo/counterlol.org" : "4,722,060",
  "http://www.alexa.com/siteinfo/picklol.net" : "7,679,714",
  "http://www.alexa.com/siteinfo/counterpicker.com" : "12,461,834"
}

Wednesday, October 17, 2012

xPage: Optimize Uploaded Image

I had a task to upload images in xPage. The next one is to optimize image lossless. User upload the image in to the Domino media library and the image optimizing on the fly.

Unfortunately there is no good Java solution for lossless optimization of images. There are set of solution to use third party command line programs and run it from java. The problem is that you need to install this program on the server, many of them supports only one OS, so if you have Domino server on the windows and then would move to the Linux (or vice verse) you got a problem.

I decide to use online optimizer. It looks like there is no good paid online services with a good API. So I start from the free one. It is well known Yahoo! Smush.it.

Smush.it has no API, but there is a guy who create stand alone java API for Smush.it service. He did it in the way of command line tool, but it could be used as API in your application.

I like it! The only one problem is that program out process information (log) directly in to the System.out. I need some information to be printed in to my log.nsf and some information to be returned to the user. So I add ability to put StringBuilder object in to the Smush.it API.  

Code example:

//log and statistic contains information 
//about process and compression result 
// 
//file - file to optimize, 
//generally opt rewrite file, but not in all cases. 
//Look "Important" section 
// 
//opt - optimized file

StringBuilder log = new StringBuilder();
StringBuilder statistic = new StringBuilder();

SmushIt smushIt = new SmushIt();
smushIt.setVerbose(log);
smushIt.setVerboseStatistic(statistic);     
smushIt.addFile(file.getCanonicalPath());
List<smushitresultvo> smushItResultVos = smushIt.smush();

ImageDownloader imageDownloader = 
 new ImageDownloader(file.getParent());
imageDownloader.setVerbose(log);

File opt = imageDownloader.download(smushItResultVos.get(0));      

StringBuilder log variable after running code:

Smushing files:

C:\Windows\Temp\notesE3A053\xspupload\0001.jpg

Adding file:C:\Windows\Temp\notesE3A053\xspupload\0001.jpg
{"src":"0b2c68eb%2F0001.jpg","src_size":40895,
"dest":"http:\/\/ysmushit.zenfs.com\
/results\/0b2c68eb%2Fsmush%2F0001.jpg",
"dest_size":38749,
"percent":"5.25","id":""}

Downloaded smushed image - 
http://ysmushit.zenfs.com/results/0b2c68eb%2Fsmush%2F0001.jpg
Saved image - C:\Windows\TEMP\notesE3A053\xspupload\0001.jpg

StringBuilder statistic variable after running code:

Source Image:0001.jpg
Source image size:40895
Smushed image size:38749
Percentage saving:5.25

Projects on github:
https://github.com/andriykuba/smushit
https://github.com/abhirama/smushit

Thursday, October 11, 2012

Custom File Upload in the xPage. Java. Backend.

There are a lot of articles about custom file upload with xPages. Most of them are about JavaScript. They use Java classes, so convert that code in to the Java is not problematic.

It's very easy to do in backend java code within xPages. The only one miss is that we could not write to the file attachment directly from the request. We still need to use a file. Thanks to xPage - it handle server temp files himself.

The code:

public void process() throws Exception {
 HttpServletRequest request = getRequest();
 
 Document document =
  getEs().createDocument().getDocument();
 document.replaceItemValue("Form", "picture");

 Map parameters = request.getParameterMap();
 UploadedFile uploadedFile=
  (UploadedFile) parameters.get("upload");
 document.replaceItemValue(
  "FileName",
  uploadedFile.getClientFileName());
 
 File tmpFile = uploadedFile.getServerFile();
 File fileToUpload = new File(
   tmpFile.getParentFile().getAbsolutePath().
   concat(java.io.File.separator).
   concat(uploadedFile.getClientFileName())); 
 
 boolean success = tmpFile.renameTo(fileToUpload); 
 addAttachment(document, success?fileToUpload:tmpFile);
 fileToUpload.renameTo(tmpFile);
 
 document.save(true, true);
}

private void addAttachment(Document document, File file)
 throws Exception{
 RichTextItem item = document.createRichTextItem("Body");
 item.embedObject(
  EmbeddedObject.EMBED_ATTACHMENT,
  "", 
  file.getCanonicalPath(), null);   
}

Look http://lotusandjava.blogspot.com/2012/09/accessing-xpages-global-objects-in-java.html to find how to get request

Saturday, October 6, 2012

It looks like Planet Lotus users are more familar with programming languages than with natural.

True code header have better rate:



CKFinder for Domino. Downloading

CKFinder have two options to download files (images) - by request to the server "connector" command processor and by direct downloading.

Request to the "connector" ("ckfinder-connector-url\connector.xsp?command=Download...") is not accessible for Domino.

For direct download CKFinder use file(image) link with the "?download" command. Let's modify this way for allowing CKFinder to "download" files from the Domino server.

Browser would download file in the case if "content-disposition" header available (and filled). We need to have ability to open file (no "content-disposition" header) and to download file ("content-disposition" header present). Let assume we have some database with web view "web-files" for open files on the web. Then we will need another one, completely the same, view "web-download" for downloading files and HTTP response headers rule for  adding "content-disposition" header.

HTTP response headers rule:
Incoming URL pattern: */web-download/*
Custom headers:
            Name: content-disposition 
            Value: attachment

Now, when you will open file "web-files/companylogo.jpg", then browser will show it, and when you open file "web-files/companylogo.jpg", then browser will ask to save it.

Domino configured. Now we need to modify ckfinder.js to allow it to load files from another url. I am using "url" attribute of "ResourceType" tag in the response of "Init" command to put files url. So I  add "download" attribute to the "ResourceType" tag to put files download url.

ckfinder.js with modification that supports "download" attribute: 

p.resourceTypes.push(new a.aL.ResourceType(p, {
 name: t.getNamedItem('name').value,
 url: t.getNamedItem('url').value,
 
 //Modification
 download: t.getNamedItem('download').value,
 
 hasChildren: t.getNamedItem('hasChildren').value,
 allowedExtensions: 
  t.getNamedItem('allowedExtensions').value,
 deniedExtensions: 
  t.getNamedItem('deniedExtensions').value,
 acl: t.getNamedItem('acl').value,
 hash: t.getNamedItem('hash').value,
 maxSize: t.getNamedItem('maxSize').value
}));

And

a.aL.ResourceType = function (q, r) {
 var s = this;
 s.app = q;
 s.name = r.name;
 s.url = r.url;
 
 //Modification
 s.download = r.download;
 
 s.hasChildren = r.hasChildren === 'true';
 s.defaultView = 'Thumbnails';
 s.allowedExtensions = r.allowedExtensions;
 s.deniedExtensions = r.deniedExtensions;
 s.oT = p(r.allowedExtensions);
 s.ms = p(r.deniedExtensions);
 s.nS = r.acl;
 s.hash = r.hash;
 s.maxSize = r.maxSize;
};

Now we need to change generation of download url in he CKFinder:

if (R.config.directDownload){
 //Modification
 var filename = encodeURIComponent(S.name);
 
 var basenanme = 
 filename.substring(0, filename.lastIndexOf('.'));
 
 T = S.folder.getResourceType().download + 
 basenanme+'/$file/'+filename;

 //original CKFinder String
 //T = S.folder.getUrl() + S.name + '?download';
}

That's all.

Friday, October 5, 2012

CKFinder for Domino. Images (and Files)

CKFinder open an image in the same way as a thumbnail. So we have exactly the same problem like for thumbnails in Domino.

CKFinder construct link to the file like "base-file-url\filename". In Domino, we have access to the attachment with the help of "\$file\" path. So we must to have URL like:
"base-file-url\filename\$file\filename." or "base-file-url\filename\filename" in the case of substitution.

You need to find in the ckfinder.js string like
J.push('<a href="', D.folder.getUrl(), 
encodeURIComponent(C[K].name), 
'" title="', C[K].name, '" rel="', E, '">a</a>'); 
and change it with
if (!F || F(C[K])) {   
 var filename = encodeURIComponent(C[K].name);
 var basenanme = filename.substring(0, 
  filename.lastIndexOf('.'));
 var url = D.folder.getResourceType().url 
  + basenanme+'/$file/'+filename;
 
 J.push('<a href="', url, '" title="', C[K].name, 
  '" rel="', E, '">a</a>');                    
 if (C[K].isSameFile(D)) H = I;
 I++;
}
That will change image url. You also need to change File url. Find
if (!W.open(S.folder.getUrl() + 
 encodeURIComponent(S.name), '_blank', V)) 
 R.msgDialog('', R.lang.ErrorMsg.oo);

and change it with

var filename = encodeURIComponent(S.name);
var basenanme = filename.substring(0, filename.lastIndexOf('.'));
var url = S.folder.getResourceType().download + basenanme+
 '/$file/'+filename;
if (!W.open(url, '_blank', V)) 
 R.msgDialog('', R.lang.ErrorMsg.oo);

CKFinder for Domino. Thumbnails.

CKFinder have two options to show thumbnails - by request to the server "connector" command processor and by direct downloading.

Request to the "connector" ("ckfinder-connector-url\connector.xsp?command=Thumbnails...") is not accessible for Domino. Reading thumbnail attachment on the server and return data as result of the command is expensive operation for the server.

CKFinder construct direct download like "thumb-base-url\filename?hash=.....". In Domino, we have access to the attachment with the help of "\$file\" path. So we must to have URL like:
"thumb-bas-url\filename\$file\filename?Open&hash=....." 

Or better:
"thumb-bas-url\filename-thumb-without-ext\$file\filename-thumb?Open&hash=....." 

In the case if will use substitution rules for fine url:
"thumb-bas-url\filename-thumb-without-ext\filename-thumb?Open&hash=....." 

You need to find in the ckfinder.js  "getThumbnailUrl" function and modify code in the
"L && N.config.thumbsDirectAccess"
condition:

if (L && N.config.thumbsDirectAccess) {
     var filename = encodeURIComponent(M);
     var dotIndex = filename.lastIndexOf('.');
     var ext = filename.substring(dotIndex+1);
     var basenanme = filename.substring(0, dotIndex);
     return N.config.thumbsUrl + basenanme 
         + '-thumb/$file/'
         + basenanme + '-thumb.' + ext
         + (!K ? '' : '?Open&hash='
         + N.getResourceType(R.folder.type).hash
         + '&fileHash=' + P);
}

Wednesday, October 3, 2012

xPage java.lang.NoClassDefFoundError

Suddenly got "java.lang.NoClassDefFoundError" error on my xPage for the class from "Java" design area. The day before it works without problems.

Project clean, rebuild does not help.  Server restart does not help. I read that Recompile code when opening in designer (xPages) solution helps for someone, unfortunately not for me.

The only one solution helps is to rename class that was not found. I am lucky to have only one such class and I am afraid to get this error again for all of them.


... maybe I will try to move code to the WEB-INF/src ...

My Client version is "20120703.0900-T00099SHF-FP2 (Release 8.5.3FP2 SHF99) "

Friday, September 28, 2012

CKFinder for Domino. First step.

I am trying to get CKFinder to work with Domino.

I saw the post "ckeditor 3.2, ckfinder 1.4.3 and Domino" but it is unavailable 2nd day, so I am looking himself in to this point.

First problem

CKFinder add some command to the end of it's URL, that domino server do not like:
 "?t=XYZ".  

Just remove it:
open ckfinder.js, look for something like "f={jY:'C7OA1WG',_:{}," and replace it on "f={_:{}," (delete jY:'C7OA1WG')

CKFinder also use command syntax like "?command=..". It's also a little trouble for domino.

Replace "?command=.." to "?Open&command=.." in the ckfinder.js

Second problem

I am trying to create server side command handlers for CKFinder.
"INIT" command example"

<?xml version="1.0" encoding="utf-8"?>
<Connector>
<Error number="0" />
<ConnectorInfo enabled="true" s="" c="" thumbsEnabled="true"  
thumbsUrl="/userfiles/_thumbs/" thumbsDirectAccess="false" />
<ResourceTypes>
<ResourceType name="Files" url="/userfiles/files/" 
allowedExtensions="7z,aiff,asf,avi,bmp,csv,doc,fla,flv,gif" 
deniedExtensions="" defaultView="Thumbnails" hash="654e8f3600949355"  
hasChildren="true" acl="17" />
<ResourceType name="Images" url="/userfiles/images/"  
allowedExtensions="bmp,gif,jpeg,jpg,png" 
deniedExtensions="" defaultView="Thumbnails" hash="4d8ddfd385d0952b" 
hasChildren="true" acl="17" />
<ResourceType name="Flash" url="/userfiles/flash/"  
allowedExtensions="swf,flv" 
deniedExtensions="" defaultView="Thumbnails" hash="a2d473ff04429cc5" 
hasChildren="true" acl="17" />
</ResourceTypes>
</Connector>

This example born errors in real life:

Error:
TypeError: t.selectSingleNode(v + "@imgWidth") is null

Fix:
"Connector/ConnectorInfo" node must have "imgWidth" attribute (as well as "imgHeight") in the command "init" resonse

Error:
TypeError: t.getNamedItem("maxSize") is null

Reason:
"Connector/ResourceTypes/ResourceType" node must have "maxSize" attribute in the command "init" resonse

So the correct "INIT" response must be like

<?xml version="1.0" encoding="utf-8"?>
<Connector>
<Error number="0" />
<ConnectorInfo imgHeight="100" imgWidth="100" enabled="true" s="" c=""  
thumbsEnabled="true" thumbsUrl="/userfiles/_thumbs/" 
thumbsDirectAccess="false" />
<ResourceTypes>
<ResourceType name="Files" url="/userfiles/files/"  
allowedExtensions="7z,aiff,asf,avi,bmp,csv,doc,fla,flv,gif" 
deniedExtensions="" defaultView="Thumbnails" hash="654e8f3600949355"  
hasChildren="true" acl="17"  maxSize="100"/>
<ResourceType name="Images" url="/userfiles/images/"  
allowedExtensions="bmp,gif,jpeg,jpg,png" 
deniedExtensions="" defaultView="Thumbnails" hash="4d8ddfd385d0952b" 
hasChildren="true" acl="17" maxSize="100"/>
<ResourceType name="Flash" url="/userfiles/flash/" 
allowedExtensions="swf,flv" 
deniedExtensions="" defaultView="Thumbnails" hash="a2d473ff04429cc5"  
hasChildren="true" acl="17" maxSize="100"/>
</ResourceTypes>
</Connector>

Thursday, September 27, 2012

CKFinder in Domino

I need to add some image library to use it with CKEditor in domino.

The best I found is CKFinder (it is not free). I did not find a good media library for build it up on the Domino.

CKFinder also have some troubles in the case of  work with Domino.

Do someone know a good media library?  I would prefer some client side library that communicate with server through  JSON or XML (like CKFinder).

Maybe some one have a nice experience with CKFinder on Domino ?

Tuesday, September 25, 2012

xPage in DXL

Domino export xPage's (java area, libs, xPages actually) in to DXL as base64 with some pre header.  This does not allow to change DXL and import it back. More of then, extracting real base64 become hard task because there is no any information about that "pre-header" in DXL.

I found similar question on the stackoverflow: http://stackoverflow.com/questions/9929325/encoding-scheme-for-ssjs-library-when-exported-via-dxl

Sunday, September 23, 2012

Export Design DXL

Export design DXL feature has been added to the DominoJavaSyncer:

https://github.com/andriykuba/DominoJavaSyncer/wiki/Export-design-DXL

Orphaned agent data in Notes 8.5

I have export of DXL from my database and found many orphaned agent data. It's "agentdata" tag that does not follow "agent" tag.

First of all I check help: Note also that the agentdata element immediately follows the agent element, but is not contained by it.

Second - look for a possible problem and solution. Take attention, "In order for the utility to clean up orphaned Agent Data Notes, you must have at least one LotusScript agent in the database.". I spend half of our until detect this. 


Friday, September 21, 2012

How to print any data in XPage output

I was looking for a solution for output clean data in xPage without any tags.

Nice solution is present in the first comment to this post. In the case you need few xPage with output special data, better to create special base class and then just extend it.

More under cut.

Accessing XPages global objects in Java (extended)

There is nice post "Accessing XPages global objects in Java". There is a little more information about returned objects.

It's a good idea to create some base class to extend it for all classes that need access to global xPage objects.

So I take variables from that articles and add Request and Response objects also.

Look more for the source.

Monday, September 17, 2012

Synchronize database resources with folders

The task I have was to update CKEditor that we have in our app.

And yes - there is not possible to use server file system for me, only nsf.

A long time ago (1 year) I was upload CKEditor using WebDAV. There is only way that store folder structure in the file names of resources in .nsf. This days configuration of WebDAV was not allowed for me (yes, I have very strict access to the server) . So I need to install local (development) domino server, configure WebDAV, upload files, do copy of database with uploaded files on the main server .....

To much work, and what if I would need it again in few month ?

So I decide to wide my Domino Java Syncer utility to do image\css\file synchronization.

You could use it if you have similar task.

In a short:


  

Friday, September 7, 2012

How to use Velocity in xPages

We are using velocity in our project for build some HTML fro some templates.

There was a problem with using it in the Java libraries. Look at this post to find problem description and solution.

Now we want to use velocity in the xPage context. There is also a little trouble:

at java.lang.SecurityManager.checkPermission(SecurityManager.java:544)
at java.lang.Thread.getContextClassLoader(Thread.java:456)
at org.apache.velocity.util.ClassUtils.getClass(ClassUtils.java:68)


This problem could be resolved  by adding next string in to the java.policy:

permission java.lang.RuntimePermission "getClassLoader";

We could not edit java.policy unfortunately. So we resolve it in the next way.

1. Download velocity source

2. Find place of error (at org.apache.velocity.util.ClassUtils.getClass(ClassUtils.java:68)):
ClassLoader loader = Thread.currentThread().getContextClassLoader();

3. Replace this string with the xPage classloader initialization:
ClassLoader cl = com.ibm.domino.xsp.module.nsf.NotesContext.getCurrent().getModule().getModuleClassLoader();

4. Add appropriate library for compile velocity source with this new class.  You will need
Domino\osgi\shared\eclipse\plugins\com.ibm.xsp.domino_8.5.3.20110915-2025\lwpd.xsp.domino.jar
or similar

5. Compile new velocity jar from modified source.

Well done! You could upload velocity jar in to the WebContent\WEB-INF\lib and use it in the xPage context.

Domino Java Syncer Documentation

I moved documentation from the document format in to the wiki. So you could find actual documentation on the git hub wiki