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.