Powered By Blogger

Thursday, December 30, 2010

Company home specific to Tenant

/**
* Gets the Company Home
*
* @return company home node ref
*/
public NodeRef getCompanyHome()
{
String tenantDomain = tenantAdminService.getCurrentUserDomain();
NodeRef companyHomeRef = companyHomeRefs.get(tenantDomain);
if (companyHomeRef == null)
{
companyHomeRef = AuthenticationUtil.runAs(new RunAsWork()
{
public NodeRef doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback()
{
public NodeRef execute() throws Exception
{
List refs = searchService.selectNodes(nodeService.getRootNode(companyHomeStore), companyHomePath, null, namespaceService, false);
if (refs.size() != 1)
{
throw new IllegalStateException("Invalid company home path: " + companyHomePath + " - found: " + refs.size());
}
return refs.get(0);
}
}, true);
}
}, AuthenticationUtil.getSystemUserName());
companyHomeRefs.put(tenantDomain, companyHomeRef);
}
return companyHomeRef;
}



The above code can be found in the class Repository.class

Sunday, December 26, 2010

Changing the content Type of existing content

/**
* Code for specialising the content Type
* @param registry
* @param actionedUponNodeRef
* @param destinationType
* @return
*/
public static boolean specialiseType(ServiceRegistry registry, NodeRef actionedUponNodeRef ,QName destinationType )
{
boolean specialise = false;
if (registry.getNodeService().exists(actionedUponNodeRef) == true)
{
// Get the type of the node
QName currentType = registry.getNodeService().getType(actionedUponNodeRef);

// Ensure that we are performing a specialise
if (currentType.equals(destinationType) == false &&
registry.getDictionaryService().isSubClass(destinationType, currentType) == true)
{
// Specialise the type of the node
registry.getNodeService().setType(actionedUponNodeRef, destinationType);
specialise = true;
}
}
return specialise;
}

Monday, December 20, 2010

Why company Home is referred as app:company_home in the path queries

# Spaces Configuration
spaces.store=workspace://SpacesStore
spaces.company_home.childname=app:company_home
spaces.guest_home.childname=app:guest_home
spaces.dictionary.childname=app:dictionary
spaces.templates.childname=app:space_templates
spaces.imapConfig.childname=app:imap_configs
spaces.imap_templates.childname=app:imap_templates
spaces.emailActions.childname=app:email_actions
spaces.searchAction.childname=cm:search
spaces.templates.content.childname=app:content_templates
spaces.templates.email.childname=app:email_templates
spaces.templates.email.invite1.childname=app:invite_email_templates
spaces.templates.email.notify.childname=app:notify_email_templates
spaces.templates.rss.childname=app:rss_templates
spaces.savedsearches.childname=app:saved_searches
spaces.scripts.childname=app:scripts
spaces.wcm.childname=app:wcm
spaces.wcm_content_forms.childname=app:wcm_forms
spaces.content_forms.childname=app:forms
spaces.user_homes.childname=app:user_homes
spaces.sites.childname=st:sites
spaces.templates.email.invite.childname=cm:invite
spaces.rendition.rendering_actions.childname=app:rendering_actions
spaces.wcm_deployed.childname=cm:wcm_deployed
spaces.transfers.childname=app:transfers
spaces.transfer_groups.childname=app:transfer_groups
spaces.transfer_temp.childname=app:temp
spaces.inbound_transfer_records.childname=app:inbound_transfer_records
spaces.outbound_transfer_records.childname=app:outbound_transfer_records



The above are the keys found in repository.properties.
Since companyhome is referred in property file with app:company_home and in the spring configuration files it is used.

Thursday, December 16, 2010

Default objects of WebScript

Alfresco webscript provides some the fields access in the ftl i,e response.
like webscript,format,args,argsM,headers,url,msg.


This is achieved in the class AbstractWebScript. That is the reason our webscript should extend the DeclarativeWebScript, DeclarativeWebScript in turn extends the AbstractWebScript.


*/
protected Map createScriptParameters(WebScriptRequest req, WebScriptResponse res, ScriptDetails script, Map customParams)
{
Map params = new HashMap(32, 1.0f);

// add web script parameters
params.put("webscript", req.getServiceMatch().getWebScript().getDescription());
params.put("format", new FormatModel(container.getFormatRegistry(), req.getFormat()));
params.put("args", createArgs(req));
params.put("argsM", createArgsM(req));
params.put("headers", createHeaders(req));
params.put("headersM", createHeadersM(req));
params.put("guest", req.isGuest());
params.put("url", new URLModel(req));
params.put("msg", getScriptMessage());

// If there is a request type specific script (e.g. *.json.js), parse
// the request according to its MIME type and add request specific
// parameters. Use the FormatReader for the generalised mime type
// corresponding to the script - not necessarily the request mime type
final String contentType = req.getContentType();

Tuesday, December 7, 2010

Builoding advanced Search Query . Refer SearchContenxt class

public String buildQuery(int minimum)
{
String query;
boolean validQuery = false;

// the QName for the well known "name" attribute
String nameAttr = Repository.escapeQName(QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, ELEMENT_NAME));

// match against content text
String text = this.text.trim();

StringBuilder fullTextBuf = new StringBuilder(64);
StringBuilder nameAttrBuf = new StringBuilder(128);
StringBuilder additionalAttrsBuf = new StringBuilder(128);

if (text.length() != 0 && text.length() >= minimum)
{
if (text.indexOf(' ') == -1 && text.charAt(0) != '"')
{
// check for existance of a special operator
boolean operatorAND = (text.charAt(0) == OP_AND);
boolean operatorNOT = (text.charAt(0) == OP_NOT);
// strip operator from term if one was found
if (operatorAND || operatorNOT)
{
text = text.substring(1);
}

if (text.length() != 0)
{
// prepend NOT operator if supplied
if (operatorNOT)
{
fullTextBuf.append(OP_NOT);
nameAttrBuf.append(OP_NOT);
}

processSearchTextAttribute(nameAttr, text, nameAttrBuf, fullTextBuf);
for (QName qname : this.simpleSearchAdditionalAttrs)
{
processSearchAttribute(qname, text, additionalAttrsBuf, false, operatorNOT);
}
}
}
else
{
// multiple word search
if (text.charAt(0) == '"' && text.charAt(text.length() - 1) == '"')
{
// as a single quoted phrase
String quotedSafeText = '"' + text.substring(1, text.length() - 1) + '"';
fullTextBuf.append("TEXT:").append(quotedSafeText);
nameAttrBuf.append("@").append(nameAttr).append(":").append(quotedSafeText);
for (QName qname : this.simpleSearchAdditionalAttrs)
{
additionalAttrsBuf.append(" @").append(
Repository.escapeQName(qname)).append(":").append(quotedSafeText);
}
}
else
{
// as individual search terms
StringTokenizer t = new StringTokenizer(text, " ");

fullTextBuf.append('(');
nameAttrBuf.append('(');
additionalAttrsBuf.append('(');

int termCount = 0;
int tokenCount = t.countTokens();
for (int i=0; i {
String term = t.nextToken();

// check for existance of a special operator
boolean operatorAND = (term.charAt(0) == OP_AND);
boolean operatorNOT = (term.charAt(0) == OP_NOT);
// strip operator from term if one was found
if (operatorAND || operatorNOT)
{
term = term.substring(1);
}

// special case for AND all terms if set (apply after operator character removed)
// note that we can't force AND if NOT operator has been set
if (operatorNOT == false)
{
operatorAND = operatorAND | this.forceAndTerms;
}

if (term.length() != 0)
{
// prepend NOT operator if supplied
if (operatorNOT)
{
fullTextBuf.append(OP_NOT);
nameAttrBuf.append(OP_NOT);
}

// prepend AND operator if supplied
if (operatorAND)
{
fullTextBuf.append(OP_AND);
nameAttrBuf.append(OP_AND);
}

processSearchTextAttribute(nameAttr, term, nameAttrBuf, fullTextBuf);
for (QName qname : this.simpleSearchAdditionalAttrs)
{
processSearchAttribute(qname, term, additionalAttrsBuf, operatorAND, operatorNOT);
}

fullTextBuf.append(' ');
nameAttrBuf.append(' ');
additionalAttrsBuf.append(' ');

termCount++;
}
}
fullTextBuf.append(')');
nameAttrBuf.append(')');
additionalAttrsBuf.append(')');
}
}

validQuery = true;
}

// match a specific PATH for space location or categories
StringBuilder pathQuery = null;
if (location != null || (categories != null && categories.length !=0))
{
pathQuery = new StringBuilder(128);
if (location != null)
{
pathQuery.append(" PATH:\"").append(location).append("\" ");
if (categories != null && categories.length != 0)
{
pathQuery.append("AND (");
}
}
if (categories != null && categories.length != 0)
{
for (int i=0; i {
pathQuery.append(" PATH:\"").append(categories[i]).append("\" ");
}
if (location != null)
{
pathQuery.append(") ");
}
}
}

// match any extra query attribute values specified
StringBuilder attributeQuery = null;
if (queryAttributes.size() != 0)
{
attributeQuery = new StringBuilder(queryAttributes.size() << 6);
for (QName qname : queryAttributes.keySet())
{
String value = queryAttributes.get(qname).trim();
if (value.length() >= minimum)
{
processSearchAttribute(qname, value, attributeQuery);
}
}

// handle the case where we did not add any attributes due to minimum length restrictions
if (attributeQuery.length() == 0)
{
attributeQuery = null;
}
}

// match any extra fixed value attributes specified
if (queryFixedValues.size() != 0)
{
if (attributeQuery == null)
{
attributeQuery = new StringBuilder(queryFixedValues.size() << 6);
}
for (QName qname : queryFixedValues.keySet())
{
String escapedName = Repository.escapeQName(qname);
String value = queryFixedValues.get(qname);
attributeQuery.append(" +@").append(escapedName)
.append(":\"").append(value).append('"');
}
}

// range attributes are a special case also
if (rangeAttributes.size() != 0)
{
if (attributeQuery == null)
{
attributeQuery = new StringBuilder(rangeAttributes.size() << 6);
}
for (QName qname : rangeAttributes.keySet())
{
String escapedName = Repository.escapeQName(qname);
RangeProperties rp = rangeAttributes.get(qname);
String value1 = LuceneQueryParser.escape(rp.lower);
String value2 = LuceneQueryParser.escape(rp.upper);
attributeQuery.append(" +@").append(escapedName)
.append(":").append(rp.inclusive ? "[" : "{").append(value1)
.append(" TO ").append(value2).append(rp.inclusive ? "]" : "}");
}
}

// mimetype is a special case - it is indexed as a special attribute it comes from the combined
// ContentData attribute of cm:content - ContentData string cannot be searched directly
if (mimeType != null && mimeType.length() != 0)
{
if (attributeQuery == null)
{
attributeQuery = new StringBuilder(64);
}
String escapedName = Repository.escapeQName(QName.createQName(ContentModel.PROP_CONTENT + ".mimetype"));
attributeQuery.append(" +@").append(escapedName)
.append(":").append(mimeType);
}

// match against appropriate content type
String fileTypeQuery;
if (contentType != null)
{
fileTypeQuery = " TYPE:\"" + contentType + "\" ";
}
else
{
// default to cm:content
fileTypeQuery = " TYPE:\"{" + NamespaceService.CONTENT_MODEL_1_0_URI + "}content\" ";
}

// match against appropriate folder type
String folderTypeQuery;
if (folderType != null)
{
folderTypeQuery = " TYPE:\"" + folderType + "\" ";
}
else
{
folderTypeQuery = " TYPE:\"{" + NamespaceService.CONTENT_MODEL_1_0_URI + "}folder\" ";
}

String fullTextQuery = fullTextBuf.toString();
String nameAttrQuery = nameAttrBuf.toString();
String additionalAttrsQuery =
(this.simpleSearchAdditionalAttrs.size() != 0) ? additionalAttrsBuf.toString() : "";

if (text.length() != 0 && text.length() >= minimum)
{
// text query for name and/or full text specified
switch (mode)
{
case SearchContext.SEARCH_ALL:
query = '(' + fileTypeQuery + " AND " + '(' + nameAttrQuery + ' ' + additionalAttrsQuery + ' ' + fullTextQuery + ')' + ')' +
' ' +
'(' + folderTypeQuery + " AND " + '(' + nameAttrQuery + ' ' + additionalAttrsQuery + "))";
break;

case SearchContext.SEARCH_FILE_NAMES:
query = fileTypeQuery + " AND " + nameAttrQuery;
break;

case SearchContext.SEARCH_FILE_NAMES_CONTENTS:
query = fileTypeQuery + " AND " + '(' + nameAttrQuery + ' ' + fullTextQuery + ')';
break;

case SearchContext.SEARCH_SPACE_NAMES:
query = folderTypeQuery + " AND " + nameAttrQuery;
break;

default:
throw new IllegalStateException("Unknown search mode specified: " + mode);
}
}
else
{
// no text query specified - must be an attribute/value query only
switch (mode)
{
case SearchContext.SEARCH_ALL:
query = '(' + fileTypeQuery + ' ' + folderTypeQuery + ')';
break;

case SearchContext.SEARCH_FILE_NAMES:
case SearchContext.SEARCH_FILE_NAMES_CONTENTS:
query = fileTypeQuery;
break;

case SearchContext.SEARCH_SPACE_NAMES:
query = folderTypeQuery;
break;

default:
throw new IllegalStateException("Unknown search mode specified: " + mode);
}
}

// match entire query against any additional attributes specified
if (attributeQuery != null)
{
query = attributeQuery + " AND (" + query + ')';
}

// match entire query against any specified paths
if (pathQuery != null)
{
query = "(" + pathQuery + ") AND (" + query + ')';
}

// check that we have a query worth executing - if we have no attributes, paths or text/name search
// then we'll only have a search against files/type TYPE which does nothing by itself!
validQuery = validQuery | (attributeQuery != null) | (pathQuery != null);
if (validQuery == false)
{
query = null;
}

if (logger.isDebugEnabled())
logger.debug("Query:\r\n" + query);

return query;
}

Example to use the SearchParameters in Alfresco with maximum limit and the permission evaluation

/**
* Search for a list of nodes using the specific search context
*
* @param searchContext To use to perform the search
*/
private void searchBrowseNodes(SearchContext searchContext)
{
long startTime = 0;
if (logger.isDebugEnabled())
startTime = System.currentTimeMillis();

// get the searcher object to build the query
String query = searchContext.buildQuery(getMinimumSearchLength());
if (query == null)
{
// failed to build a valid query, the user probably did not enter the
// minimum text required to construct a valid search
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(FacesContext.getCurrentInstance(), MSG_SEARCH_MINIMUM),
new Object[] {getMinimumSearchLength()}));
this.containerNodes = Collections.emptyList();
this.contentNodes = Collections.emptyList();
return;
}

// perform the search against the repo
UserTransaction tx = null;
ResultSet results = null;
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance(), true);
tx.begin();

// build up the search parameters
SearchParameters sp = new SearchParameters();
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery(query);
sp.addStore(Repository.getStoreRef());

// limit search results size as configured
int searchLimit = Application.getClientConfig(FacesContext.getCurrentInstance()).getSearchMaxResults();
if (searchLimit > 0)
{
sp.setLimitBy(LimitBy.FINAL_SIZE);
sp.setLimit(searchLimit);
}

results = this.getSearchService().query(sp);
if (logger.isDebugEnabled())
logger.debug("Search results returned: " + results.length());

// create a list of items from the results
this.containerNodes = new ArrayList(results.length());
this.contentNodes = new ArrayList(results.length());
if (results.length() != 0)
{
// in case of dynamic config, only lookup once
Set nodeEventListeners = getNodeEventListeners();

for (ResultSetRow row: results)
{
NodeRef nodeRef = row.getNodeRef();

if (this.getNodeService().exists(nodeRef))
{
// find it's type so we can see if it's a node we are interested in
QName type = this.getNodeService().getType(nodeRef);

// make sure the type is defined in the data dictionary
TypeDefinition typeDef = this.getDictionaryService().getType(type);

if (typeDef != null)
{
MapNode node = null;

// look for Space or File nodes
if (this.getDictionaryService().isSubClass(type, ContentModel.TYPE_FOLDER) &&
this.getDictionaryService().isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER) == false)
{
// create our Node representation
node = new MapNode(nodeRef, this.getNodeService(), false);

node.addPropertyResolver("path", this.resolverPath);
node.addPropertyResolver("displayPath", this.resolverDisplayPath);
node.addPropertyResolver("icon", this.resolverSpaceIcon);
node.addPropertyResolver("smallIcon", this.resolverSmallIcon);

this.containerNodes.add(node);
}
else if (this.getDictionaryService().isSubClass(type, ContentModel.TYPE_CONTENT))
{
// create our Node representation
node = new MapNode(nodeRef, this.getNodeService(), false);

setupCommonBindingProperties(node);

node.addPropertyResolver("path", this.resolverPath);
node.addPropertyResolver("displayPath", this.resolverDisplayPath);

this.contentNodes.add(node);
}
// look for File Link object node
else if (ApplicationModel.TYPE_FILELINK.equals(type))
{
// create our File Link Node representation
node = new MapNode(nodeRef, this.getNodeService(), false);
// only display the user has the permissions to navigate to the target of the link
NodeRef destRef = (NodeRef)node.getProperties().get(ContentModel.PROP_LINK_DESTINATION);
if (new Node(destRef).hasPermission(PermissionService.READ) == true)
{
node.addPropertyResolver("url", this.resolverLinkUrl);
node.addPropertyResolver("downloadUrl", this.resolverLinkDownload);
node.addPropertyResolver("webdavUrl", this.resolverLinkWebdavUrl);
node.addPropertyResolver("cifsPath", this.resolverLinkCifsPath);
node.addPropertyResolver("fileType16", this.resolverFileType16);
node.addPropertyResolver("fileType32", this.resolverFileType32);
node.addPropertyResolver("size", this.resolverSize);
node.addPropertyResolver("lang", this.resolverLang);
node.addPropertyResolver("path", this.resolverPath);
node.addPropertyResolver("displayPath", this.resolverDisplayPath);

this.contentNodes.add(node);
}
}
else if (ApplicationModel.TYPE_FOLDERLINK.equals(type))
{
// create our Folder Link Node representation
node = new MapNode(nodeRef, this.getNodeService(), false);
// only display the user has the permissions to navigate to the target of the link
NodeRef destRef = (NodeRef)node.getProperties().get(ContentModel.PROP_LINK_DESTINATION);
if (new Node(destRef).hasPermission(PermissionService.READ) == true)
{
node.addPropertyResolver("icon", this.resolverSpaceIcon);
node.addPropertyResolver("smallIcon", this.resolverSmallIcon);
node.addPropertyResolver("path", this.resolverPath);
node.addPropertyResolver("displayPath", this.resolverDisplayPath);

this.containerNodes.add(node);
}
}

// inform any listeners that a Node wrapper has been created
if (node != null)
{
for (NodeEventListener listener : nodeEventListeners)
{
listener.created(node, type);
}
}
}
else
{
if (logger.isWarnEnabled())
logger.warn("Found invalid object in database: id = " + nodeRef + ", type = " + type);
}
}
else
{
if (logger.isWarnEnabled())
logger.warn("Missing object returned from search indexes: id = " + nodeRef + " search query: " + query);
}
}
}

// commit the transaction
tx.commit();
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {refErr.getNodeRef()}), refErr );
this.containerNodes = Collections.emptyList();
this.contentNodes = Collections.emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
catch (SearcherException serr)
{
logger.info("Search failed for: " + query, serr);
Utils.addErrorMessage(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_QUERY));
this.containerNodes = Collections.emptyList();
this.contentNodes = Collections.emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_SEARCH), new Object[] {err.getMessage()}), err );
this.containerNodes = Collections.emptyList();
this.contentNodes = Collections.emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
finally
{
if (results != null)
{
results.close();
}
}

if (logger.isDebugEnabled())
{
long endTime = System.currentTimeMillis();
logger.debug("Time to query and build map nodes: " + (endTime - startTime) + "ms");
}
}


This code you can find in BrowseBean class.

org.alfresco.repo.web.scripts WebScript package

org.alfresco.repo.web.scripts

Above package is having the information related to the discussion,facebook intgration,blog,portlet , rule deletion, rule creation and Some test cases for jsonRest post etc

Version History

VersionHistory versionHistory = entry1.getVersionHistory();


// for each version, output the node as it was versioned
for (VersionIterator versionIterator = versionHistory.getAllVersions(); versionIterator.hasNext(); )
{
Version version = versionIterator.nextVersion();
for (NodeIterator nodeIterator = version.getNodes(); nodeIterator.hasNext(); )
{
Node versionedNode = nodeIterator.nextNode();
System.out.println(" Version label: " + version.getName());
System.out.println(" created: " + version.getCreated().getTime());
System.out.println(" restrict: " versionedNode.getProperty("wiki:restrict").getString());
System.out.println(" content: " versionedNode.getProperty("cm:content").getString());
}
}

Monday, December 6, 2010

Permission check in the content search

There is a time constraint applied to permission evaluations. This is set in the repository configuration, not on the QueryParameters.

When we search for the content then parallely even the permission check is also done in alfresco. SO in the repository whatever the time we specify only that much of time is taken for the permission evaluation, after that the remaining nodes will be ommitted.

For this evaluate SearchParameters class.

Autheticating to Alfresco from servlet

* Perform an authentication for the servlet request URI. Processing any "ticket" or
* "guest" URL arguments.
*
* @return AuthenticationStatus
*
* @throws IOException
*/
public AuthenticationStatus servletAuthenticate(HttpServletRequest req, HttpServletResponse res,
boolean redirectToLoginPage) throws IOException
{
AuthenticationStatus status;

// see if a ticket or a force Guest parameter has been supplied
String ticket = req.getParameter(ARG_TICKET);
if (ticket != null && ticket.length() != 0)
{
status = AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
}
else
{
boolean forceGuest = false;
String guest = req.getParameter(ARG_GUEST);
if (guest != null)
{
forceGuest = Boolean.parseBoolean(guest);
}
status = AuthenticationHelper.authenticate(getServletContext(), req, res, forceGuest);
}
if (status == AuthenticationStatus.Failure && redirectToLoginPage)
{
// authentication failed - now need to display the login page to the user, if asked to
redirectToLoginPage(req, res, getServletContext());
}

return status;
}

Freemarker default objects

TemplateContentServlet is the class responsible for exposing the default objects of the FTL. BaseTemplateContentServlet will have the code related to prepare the model and expose the content.


/**
* Build the model that to process the template against.
*


* The model includes the usual template root objects such as 'companyhome', 'userhome',
* 'person' and also includes the node specified on the servlet URL as 'space' and 'document'
*
* @param services ServiceRegistry
* @param req Http request - for accessing Session and url args
* @param templateRef NodeRef of the template itself
* @param nodeRef NodeRef of the space/document to process template against
*
* @return an object model ready for executing template against
*/
@SuppressWarnings("unchecked")
private Map getModel(ServiceRegistry services, HttpServletRequest req, NodeRef templateRef, NodeRef nodeRef)
{
// build FreeMarker default model and merge
Map root = buildModel(services, req, templateRef);

// put the current NodeRef in as "space" and "document"
root.put("space", nodeRef);
root.put("document", nodeRef);

// add URL arguments as a map called 'args' to the root of the model
Map args = new HashMap(8, 1.0f);
Enumeration names = req.getParameterNames();
while (names.hasMoreElements())
{
String name = (String)names.nextElement();
try
{
args.put(name, new String(req.getParameter(name).getBytes(), "UTF-8"));
}
catch (UnsupportedEncodingException err) {}
}
root.put("args", args);

// Add the image resolver
root.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver);

// method to allow client urls to be generated
root.put("url", new URLHelper(req));

return root;
}

Sunday, December 5, 2010

Code to get the file size in Alfresco

public NodePropertyResolver resolverSize = new NodePropertyResolver() {
private static final long serialVersionUID = 1273541660444385276L;

public Object get(Node node) {
ContentData content = (ContentData)node.getProperties().get(ContentModel.PROP_CONTENT);
return (content != null ? new Long(content.getSize()) : 0L);
}
};


SO get the content data from the node. From the content Data extract the size of the file.

Response Headers

// set header based on filename - will force a Save As from the browse if it doesn't recognize it
// this is better than the default response of the browser trying to display the contents
res.setHeader("Content-Disposition", headerValue);


// set mimetype for the content and the character encoding + length for the stream
res.setContentType(mimetype);
res.setContentEncoding(reader.getEncoding());
res.setHeader("Content-Length", Long.toString(reader.getSize()));


Refer to the class

ContentGet webscript to see how the data will be sent to the front end

Thursday, December 2, 2010

Clustering in Alfresco Multi Tenant Environment

Clustering in multi teanant environment is same as we do in single tenant environemnt.
Only condition we need to take care here is content store location. We should allow alfresco to use the default content store.

create patil.com patil

DOnts specify the location where it has to be created.

Some of the steps I follwed in Alfresco 3.3.3 are as below

1. start the first server as usual. by configuring dir.root. check there are no errors
2. Rename the replication file, configure remote store location as well.
configure the shared drive location

location has to be given till content store



E:/Alfresco3.3.3clustering/ServerA/alf_data/contentstore


start the server, check for exceptions. If not stop the server.

3. Now copy alf_data to serverB,keep database name same as previous one. change the index tracking to auto and give the cluster name and give the index rebuilding.Property file will have the path for the
local contentstore.
4. Restart the server.
5.stop server
5. Now again start the second server by renaming the replication.xml and using the local and shared content stores in xml with the same database.
6. Now start server A


7. Test by creating content in another server it has to be reflected in server1



Now we will move to detection of server:
There are 2 ways of doing it
1. Using default EhCache
2. Using jgroups for the configuration. It will be matter of configuration in the ehcache.xml

To start with use the default RMIdection(EhCache) which is been followed from long back.


Alfresco requires servers to discover each other on a network in order to set up cluster communications.
Before V3.1, this discovery process was done using a UDP multicast message (provided by EHCache); servers in the cluster picked
the message up and used the information to set up inter-server communication for inter-cache communication.



Now run all the test conditions to verify
1.Cache clustering : by changing the property of a content
2 Index clustering : By performing search.
3.Content replication/sharing : By checking the content created in one server exists in another server.



Now test the cluster.

Start the servers in sequence. Only when the first server is up then start the second server.


Note : Make sure not to give the tenant creation location while creating the tenant through the tenant console.
create the tenant in one server and then restart another server to make contents get created.Otherwise exception will be thrown.

Once done create the content in one store. It will be reflected in another store.

Tuesday, November 23, 2010

UploadFileServlet

/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see . */
package org.alfresco.web.app.servlet;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;

import javax.faces.context.FacesContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.util.TempFileProvider;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.ErrorBean;
import org.alfresco.web.bean.FileUploadBean;
import org.alfresco.web.config.ClientConfigElement;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.servlet.ServletRequestContext;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.config.ConfigService;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
* Servlet that takes a file uploaded via a browser and represents it as an
* UploadFileBean in the session
*
* @author gavinc
*/
public class UploadFileServlet extends BaseServlet
{
private static final long serialVersionUID = -5482538466491052875L;
private static final Log logger = LogFactory.getLog(UploadFileServlet.class);

private ConfigService configService;


/**
* @see javax.servlet.GenericServlet#init()
*/
@Override
public void init(ServletConfig sc) throws ServletException
{
super.init(sc);

WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sc.getServletContext());
this.configService = (ConfigService)ctx.getBean("webClientConfigService");
}

/**
* @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@SuppressWarnings("unchecked")
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String uploadId = null;
String returnPage = null;
final RequestContext requestContext = new ServletRequestContext(request);
boolean isMultipart = ServletFileUpload.isMultipartContent(requestContext);

try
{
AuthenticationStatus status = servletAuthenticate(request, response);
if (status == AuthenticationStatus.Failure)
{
return;
}

if (!isMultipart)
{
throw new AlfrescoRuntimeException("This servlet can only be used to handle file upload requests, make" +
"sure you have set the enctype attribute on your form to multipart/form-data");
}

if (logger.isDebugEnabled())
logger.debug("Uploading servlet servicing...");

FacesContext context = FacesContext.getCurrentInstance();
Map session = context.getExternalContext().getSessionMap();
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());

// ensure that the encoding is handled correctly
upload.setHeaderEncoding("UTF-8");

List fileItems = upload.parseRequest(request);

FileUploadBean bean = new FileUploadBean();
for (FileItem item : fileItems)
{
if(item.isFormField())
{
if (item.getFieldName().equalsIgnoreCase("return-page"))
{
returnPage = item.getString();
}
else if (item.getFieldName().equalsIgnoreCase("upload-id"))
{
uploadId = item.getString();
}
}
else
{
String filename = item.getName();
if (filename != null && filename.length() != 0)
{
if (logger.isDebugEnabled())
{
logger.debug("Processing uploaded file: " + filename);
}

// ADB-41: Ignore non-existent files i.e. 0 byte streams.
if (allowZeroByteFiles() == true || item.getSize() > 0)
{
// workaround a bug in IE where the full path is returned
// IE is only available for Windows so only check for the Windows path separator
filename = FilenameUtils.getName(filename);
final File tempFile = TempFileProvider.createTempFile("alfresco", ".upload");
item.write(tempFile);
bean.setFile(tempFile);
bean.setFileName(filename);
bean.setFilePath(tempFile.getAbsolutePath());
if (logger.isDebugEnabled())
{
logger.debug("Temp file: " + tempFile.getAbsolutePath() +
" size " + tempFile.length() +
" bytes created from upload filename: " + filename);
}
}
else
{
if (logger.isWarnEnabled())
logger.warn("Ignored file '" + filename + "' as there was no content, this is either " +
"caused by uploading an empty file or a file path that does not exist on the client.");
}
}
}
}

session.put(FileUploadBean.getKey(uploadId), bean);

if (bean.getFile() == null && uploadId != null && logger.isWarnEnabled())
{
logger.warn("no file uploaded for upload id: " + uploadId);
}

if (returnPage == null || returnPage.length() == 0)
{
throw new AlfrescoRuntimeException("return-page parameter has not been supplied");
}

if (returnPage.startsWith("javascript:"))
{
returnPage = returnPage.substring("javascript:".length());
// finally redirect
if (logger.isDebugEnabled())
{
logger.debug("Sending back javascript response " + returnPage);
}
response.setContentType(MimetypeMap.MIMETYPE_HTML);
response.setCharacterEncoding("utf-8");
final PrintWriter out = response.getWriter();
out.println("");
out.close();
}
else
{
// finally redirect
if (logger.isDebugEnabled())
logger.debug("redirecting to: " + returnPage);

response.sendRedirect(returnPage);
}

if (logger.isDebugEnabled())
logger.debug("upload complete");
}
catch (Throwable error)
{
handleUploadException(request, response, error, returnPage);
}
}

private void handleUploadException(HttpServletRequest request, HttpServletResponse response, Throwable error, String returnPage)
{
try
{
HttpSession session = request.getSession(true);
ErrorBean errorBean = (ErrorBean) session.getAttribute(ErrorBean.ERROR_BEAN_NAME);
if (errorBean == null)
{
errorBean = new ErrorBean();
session.setAttribute(ErrorBean.ERROR_BEAN_NAME, errorBean);
}
errorBean.setLastError(error);
errorBean.setReturnPage(returnPage);
}
catch (Throwable e)
{
logger.error("Error while handling upload Exception", e);
}
try
{
String errorPage = Application.getErrorPage(getServletContext());

if (logger.isDebugEnabled())
{
logger.debug("An error has occurred. Sending back response for redirecting to error page: " + errorPage);
}

response.setContentType(MimetypeMap.MIMETYPE_HTML);
response.setCharacterEncoding("utf-8");
final PrintWriter out = response.getWriter();
out.println(" ");
out.close();
}
catch (Exception e)
{
logger.error("Error while handling upload Exception", e);
}
}


private boolean allowZeroByteFiles()
{
ClientConfigElement clientConfig = (ClientConfigElement)configService.getGlobalConfig().getConfigElement(
ClientConfigElement.CONFIG_ELEMENT_ID);
return clientConfig.isZeroByteFileUploads();
}
}

UploadContentServlet

/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
package org.alfresco.web.app.servlet;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.StringTokenizer;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.encoding.ContentCharsetFinder;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* Servlet responsible for streaming content directly into the repository from the PUT request.
* The appropriate mimetype is calculated based on filename extension.
*


* The URL to the servlet should be generated thus:
*

/alfresco/upload/workspace/SpacesStore/0000-0000-0000-0000/myfile.pdf

* or
*
/alfresco/upload/myfile.pdf

*


* If the store and node id are specified in the URL then the content provided will be streamed onto the node
* using an updating writer, updating the content property value accordingly.
*


* If only the file name is specified the content will be streamed into the content store and the content data
* will be returned in the reposonse. This can then be used to update the value of a content property manually.
* Any used content will be cleared up in the usual manner.
*


* By default, the download assumes that the content is on the
* {@link org.alfresco.model.ContentModel#PROP_CONTENT content property}.

* To set the content of a specific model property, use a 'property' arg, providing the qualified name of the property.
*


* Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
* ?ticket=1234567890
*


* Guest access is currently disabled for this servlet.
*
* @author Roy Wetherall
*/
public class UploadContentServlet extends BaseServlet
{
/** Serial version UID */
private static final long serialVersionUID = 1055960980867420355L;

/** Logger */
private static Log logger = LogFactory.getLog(UploadContentServlet.class);

/** Default mime type */
protected static final String MIMETYPE_OCTET_STREAM = "application/octet-stream";

/** Argument properties */
protected static final String ARG_PROPERTY = "property";
protected static final String ARG_MIMETYPE = "mimetype";
protected static final String ARG_ENCODING = "encoding";

/**
* @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void doPut(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
if (logger.isDebugEnabled() == true)
{
String queryString = req.getQueryString();
logger.debug("Authenticating request to URL: " + req.getRequestURI()
+ ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}

AuthenticationStatus status = servletAuthenticate(req, res, false);
if (status == AuthenticationStatus.Failure || status == AuthenticationStatus.Guest)
{
res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}

// Tokenise the URI
String uri = req.getRequestURI();
uri = uri.substring(req.getContextPath().length());
StringTokenizer t = new StringTokenizer(uri, "/");
int tokenCount = t.countTokens();

t.nextToken(); // skip servlet name

// get or calculate the noderef and filename to download as
NodeRef nodeRef = null;
String filename = null;
QName propertyQName = null;

if (tokenCount == 2)
{
// filename is the only token
filename = t.nextToken();
}
else if (tokenCount == 4 || tokenCount == 5)
{
// assume 'workspace' or other NodeRef based protocol for remaining URL
// elements
StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
String id = t.nextToken();
// build noderef from the appropriate URL elements
nodeRef = new NodeRef(storeRef, id);

if (tokenCount == 5)
{
// filename is last remaining token
filename = t.nextToken();
}

// get qualified of the property to get content from - default to
// ContentModel.PROP_CONTENT
propertyQName = ContentModel.PROP_CONTENT;
String property = req.getParameter(ARG_PROPERTY);
if (property != null && property.length() != 0)
{
propertyQName = QName.createQName(property);
}
}
else
{
logger.debug("Upload URL did not contain all required args: " + uri);
res.sendError(HttpServletResponse.SC_EXPECTATION_FAILED);
return;
}

// get the services we need to retrieve the content
ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
ContentService contentService = serviceRegistry.getContentService();
PermissionService permissionService = serviceRegistry.getPermissionService();
MimetypeService mimetypeService = serviceRegistry.getMimetypeService();

InputStream is = req.getInputStream();
BufferedInputStream inputStream = new BufferedInputStream(is);

// Sort out the mimetype
String mimetype = req.getParameter(ARG_MIMETYPE);
if (mimetype == null || mimetype.length() == 0)
{
mimetype = MIMETYPE_OCTET_STREAM;
if (filename != null)
{
MimetypeService mimetypeMap = serviceRegistry.getMimetypeService();
int extIndex = filename.lastIndexOf('.');
if (extIndex != -1)
{
String ext = filename.substring(extIndex + 1);
mimetype = mimetypeService.getMimetype(ext);
}
}
}

// Get the encoding
String encoding = req.getParameter(ARG_ENCODING);
if (encoding == null || encoding.length() == 0)
{
// Get the encoding
ContentCharsetFinder charsetFinder = mimetypeService.getContentCharsetFinder();
Charset charset = charsetFinder.getCharset(inputStream, mimetype);
encoding = charset.name();
}

if (logger.isDebugEnabled())
{
if (nodeRef != null) {logger.debug("Found NodeRef: " + nodeRef.toString());}
logger.debug("For property: " + propertyQName);
logger.debug("File name: " + filename);
logger.debug("Mimetype: " + mimetype);
logger.debug("Encoding: " + encoding);
}

// Check that the user has the permissions to write the content
if (permissionService.hasPermission(nodeRef, PermissionService.WRITE_CONTENT) == AccessStatus.DENIED)
{
if (logger.isDebugEnabled() == true)
{
logger.debug("User does not have permissions to wrtie content for NodeRef: " + nodeRef.toString());
}

if (logger.isDebugEnabled())
{
logger.debug("Returning 403 Forbidden error...");
}

res.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}

// Try and get the content writer
ContentWriter writer = contentService.getWriter(nodeRef, propertyQName, true);
if (writer == null)
{
if (logger.isDebugEnabled() == true)
{
logger.debug("Content writer cannot be obtained for NodeRef: " + nodeRef.toString());
}
res.sendError(HttpServletResponse.SC_EXPECTATION_FAILED);
return;
}

// Set the mimetype and encoding
writer.setMimetype(mimetype);
writer.setEncoding(encoding);

// Stream the content into the repository
writer.putContent(inputStream);

if (logger.isDebugEnabled() == true)
{
logger.debug("Content details: " + writer.getContentData().toString());
}

// Set return status
res.getWriter().write(writer.getContentData().toString());
res.flushBuffer();

if (logger.isDebugEnabled() == true)
{
logger.debug("UploadContentServlet done");
}
}
}

Monday, November 22, 2010

File upload Alfresco




File Upload




// node reference of the folder where you want to upload , you can get it from alfresco webclient by view details action



















Sunday, November 7, 2010

Alfresco CIFS with LDAP

LDAP and CIFS: If you configure Alfresco to authenticate against LDAP
and have a requirement to use CIFS, realize that the passwords in your
LDAP directory must be either clear text or MD4, otherwise, CIFS won't
work.

Monday, July 26, 2010

Workflow Alfresco

Let me talk about Advanced workflow today.
We can start the workflow for the empty workflow package.
To start the workflow we have to extend StartWorkflowWizard
Create the empty package and then start the workflow.


In the manageTaskDialog if you have to acees any property then that property has to be
defined in the content Model.

Sunday, July 25, 2010

Things to take care related to roles in Alfresco

1. Dont use the admin to test any functionality.To avoid access denied exception.
2. Always while developing do the role based development
Dont keep it for the end.
3. Use the below code to check whether user belongs to particular group or not

final String _user = AuthenticationUtil.getRunAsUser();
AuthenticationUtil.setRunAsUserSystem();

AuthenticationUtil.setRunAsUser(_user);
return _groupSet;
4. Dont invite any user to any folder manually
5. Start development in IE6, to avoid the fixes to be done in the later stage.
6. Before starting development know each and every field, from where that data is going to come, what all are the validations to be done for the field. And where this field will be useful.

7. To start the development finalize the content model, aspects and how to use them
8. All the properties of content model have to be picked from the constant file and for all the propereties kept in the model fil Qname has to be created
9. Based on the functionalities and the modules to be designed create different model files.
10. Based on the functionality ot the modulr follow the naming conventions so that code can be easily maintained.
11. If you have to display any proerty to the front end then pass the noderef or MapNode or node to the frontEnd, from this node access the properties.

Tuesday, July 6, 2010

Alfresco users and Groups

1. Getting the logged in user

final String _user = AuthenticationUtil.getRunAsUser();


2. Getting the usernode ref from username

final NodeRef _userRef = serviceRegistry.getPersonService().getPerson(_userName);


3. Getting the groups the user belonging to user

final Set _groupSet = this.getAuthorityService().getAuthoritiesForUser(_user);