Alfresco Java code to move documents to specific - alfresco

I want to move documents attached with workflow to some specific. I have done this in java script.
var destNode = search.findNode("workspace://SpacesStore/55bbdd0e-c185-4ab4-a7e8-5e8d9701a5ed");
for (var i = 0; i < bpm_package.children.length; i++)
{
bpm_package.children[i].move(destNode);
}
But I want java version of doing same ? Please help me!
Thanks in advance.

you can use fileFolderService to move any document.There is method in fileFolderService called move.You can fine more on this on below link.
http://dev.alfresco.com/resource/docs/java/org/alfresco/service/cmr/model/FileFolderService.html
For using filefolderService you need to inject that service.Ig you are using javabackend webscript you can do it like below in any context file.
<bean id="webscript.{Path}.get" class="com.yaskawa.api.WebScript"
parent="webscript">
<property name="fileFolderService" ref="fileFolderService" />
</bean>
Below is example
FileFolderService().move(node,destNode, "NameOnDestination")
Hope this helps:)

Here is the Java equivalent:
ActivitiScriptNode bpmPackageScriptNode = (ActivitiScriptNode) delegateTask.getVariable("bpm_package");
if(bpmPackageScriptNode != null) {
NodeRef bpmPackage = bpmPackageScriptNode.getNodeRef();
List<ChildAssociationRef> children = nodeService.getChildAssocs(
bpmPackage, WorkflowModel.ASSOC_PACKAGE_CONTAINS, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef child : children) {
NodeRef childRef = child.getChildRef();
fileService.move(childRef, destinationXpath, null);
}
}
It is better to use move(...) from FileFolderService instead of NodeSerivce because of some additional checks.

Related

XmlDocument difficulties returning specific nodes/elements

first post. I hope it meets with the rules of asking questions.
I'm in a bit of bother with an xml document (its an API returned Xml). Now it uses a multitude of internet (http based) security measures which I have worked thru and I am now able to return the the top tier of nodes that are not nested.
however there are a few nodes which are nested under these and I need to return some of these values.
I'm set on using XMLDocument to do this, and I'm not interested in using XPath.
I should also note that I'm using the .Net 4.5 environment.
Example XML
<?xml version="1.0" encoding="utf-8"?>
<results>
<Info xmlns="http://xmlns.namespace">
<title>This Title</title>
<ref>
<SetId>317</SetId>
</ref>
<source>
<name>file.xxx</name>
<type>thisType</type>
<hash>cc7b99599c1bebfc4b8f12e47aba3f76</hash>
<pers>65.97602</pers>
<time>02:20:02.8527777</time>
</source>
....... Continuation which is same as above
Ok so above is the Xml that gets returned from the API, now, I can return title node no problem. What I would also like to return is any of the node values in the Element, for example the pers node value. But I only want to return one (as there are many in the existing xml further down)
Please note that there is an xmlns in the Info node which may not be allowing me to return the values.
So here is my code
using (var response = (HttpWebResponse) request.GetResponse())
{
//Get the response stream
using (Stream stream = response.GetResponseStream())
{
if (stream != null)
{
var xDoc = new XmlDocument();
var nsm = new XmlNamespaceManager(xDoc.NameTable);
nsm.AddNamespace("ns", XmlNamespace);
//Read the response stream
using (XmlReader xmlReader = XmlReader.Create(stream))
{
// This is straight forward, we just need to read the XML document and return the bits we need.
xDoc.Load(xmlReader);
XmlElement root = xDoc.DocumentElement;
var cNodes = root.SelectNodes("/results/ns:Info", nsm);
//Create a new instance of Info so that we can store any data found in the Info Properties.
var info = new Info();
// Now we have a collection of Info objects
foreach (XmlNode node in cNodes)
{
// Do some parsing or other relevant filtering here
var title = node["title"];
if (title != null)
{
info.Title = title.InnerText;
_logger.Info("This is the title returned ############# {0}", info.Title);
}
//This is the bit that is killing me as i can't return the any values in the of the sub nodes
XmlNodeList sourceNodes = node.SelectNodes("source");
foreach (XmlNode sn in sourceNodes)
{
XmlNode source = sn.SelectSingleNode("source");
{
var pers = root["pers"];
if (pers != null) info.pers = pers.InnerText;
_logger.Info("############FPS = {0}", info.pers);
}
}
}
}
Thanks in advance for any help
So I finally figured it out.
Here is the code that gets the subnodes. Basically I wasn't using my namespace identifier or my namespace for returning subnodes within the "Source" node.
For anybody else in this situation,
When you declare your name space there are to parts to it, a namespace identifier which is anything you want it to be in my case I chose "ns" and then the actual namespace in the XML file which is prefixed by xmlns and will contain something like for example: "http://xmlns.mynamespace".
So when searching subnodes inside the top level you need to declare these namespaces for the main node of the subnode you want to get.
// get the <source> subnode using the namespace to returns all <source> values
var source = node.SelectSingleNode("ns:source", nsm);
if (source != null)
{
info.SourceType = source["type"].InnerText;
info.Pers = source["pers"].InnerText;
_logger.Info("This SourceNode is {0}", info.SourceType);
_logger.Info("This PersNode is {0}", info.FramesPerSecond);
}
I hope this helps somebody else that's chasing their tails as I have.
Thanks

Iterating through xmltextreader

I have a xml in the following format.
<?xml version="1.0" encoding="UTF-8" standalone= "yes"?>
<rss>
<report name="rpt1">
<title>AAA</title>
<image></image>
<weblink></weblink>
<pdflink></pdflink>
<pdfsize></pdfsize>
</report>
<report name="rpt2">
<title>BBB</title>
<image>CCC</image>
<weblink>DDD</weblink>
<pdflink>EEE</pdflink>
<pdfsize>FFF</pdfsize>
</report>
</rss>
Now i want to iterate this xml and get the report node and from there get childnodes like title/pdflink/size etc which would be thru. looping using for loop. I want to use xmltextreader to accompalish this. I tried using while but i get only 1 loop after iterating. I dont know why. If thru for loop how do i iterate like,
for(loop when reader.element("reports)){} and then get the rest of the nodes and put them in an array or list or so. Once i get them stored in list i would want to dipaly them ina feed. which is a best way to do this? pls help.
In my case I was worried about the performance of loading a large document. What I have done is define a constructor on my objects to receive a XmlReader and hydrate - passing the reader back after it reaches a complete node.
This allows me to yield a populated object back as IEnumerable for each object as it's being read. Then I launch a new Task/Thread to handle processing that individual item and go back to processing the file.
private IEnumerable<Report> readReports(Stream reader)
{
var settings = new XmlReaderSettings();
settings.IgnoreWhitespace = true;
var xmlReader = XmlReader.Create(reader, settings);
xmlReader.MoveToContent();
xmlReader.Read();
while (!xmlReader.EOF)
{
if (xmlReader.Name.ToUpper() == "report")
yield return new Report(xmlReader);
xmlReader.Read();
}
}
public Report(XmlReader reader) : this()
{
reader.MoveToContent();
if (reader.IsEmptyElement)
{
reader.Read();
return;
}
reader.Read();
while (!reader.EOF)
{
if (reader.IsStartElement())
{
switch (reader.Name.ToLower())
{
case "order_id":
this.OrderId = reader.ReadElementContentAsString();
break;
// abreviated the rest of the fields
default:
reader.Skip();
break;
}
}
else if (reader.Name.ToLower() == "report") //this watches for the end element of the container and returns after populating all properties
return;
}
}
I would definitly appreciate any feedback from the rest of the community, if there is a better approach or if there are any errors here please let me know.

How do you change the Repository link on Alfresco Share?

In Alfresco Share, when you click the "Repository" icon in the toolbar, you're taken to:
/share/page/repository
I would like to change this link to take the user to their home folder, example:
/share/page/repository#filter=path|/User%2520Homes/g/gi/gillespie/patrick.j.gillespie
I figured this would be a simple change, however, I'm pulling my hair out trying to figure out how to change the link. Does anyone know what I edit to change that link?
Update: So I can update the link via the share-config-custom.xml file, changing this line:
<item type="link" id="repository">/repository</item>
But I'm not sure how to get the folder path information in there. Does anyone have any ideas?
This was surprisingly difficult, so I figured I'd post what I did in case anyone else has the same problem.
If you're not using hashed home folders, you can provide this functionality by simply updating your share-config.xml or share-config-custom.xml like so:
<item type="link" id="repository">/repository#filter=path|/User%2520Homes/{userid}</item>
However, if you're using hashed home folders, things become a little tricky. Instead of modifying any XML files, you'll instead create a web script to get the user's home folder path and then modify the share template file to replace the links to the repository. Below is a sample web script and the modifications to the template file that are needed in order to do this.
hfp.get.desc.xml
<webscript>
<shortname>Home Folder Path</shortname>
<description>Description here.</description>
<format default="json">argument</format>
<url>/demo/get-home-folder-path</url>
<authentication>user</authentication>
</webscript>
hfp.get.js
This script traverses up the node tree and puts together the folder's path.
var myPerson = person;//used people.getPerson("patrick.j.gillespie") for testing
var currentNode = myPerson.properties.homeFolder;
var myDir = currentNode.properties["{http://www.alfresco.org/model/content/1.0}name"];
var count = 0;
while (count < 100) { // prevent an infinite loop
currentNode = currentNode.parent;
if (currentNode === undefined || currentNode === null) {break;}
if (currentNode.properties === undefined) {break;}
myDir = currentNode.properties["{http://www.alfresco.org/model/content/1.0}name"] + "/" + myDir;
count++;
}
if (count === 100) { //something went wrong
myDir = "";
}
model.homeFolder = myDir;
hfp.get.json.ftl
{
"homeFolder": "${homeFolder}"
}
Finally, you'll need to modify the "alfresco-template.ftl" file, located in "share/WEB-INF/classes/alfresco/templates/org/alfresco/include". Near the bottom of the file, add the code below. It will call the above web script to fetch the home folder path, and then update the Repository links with the home folder link.
<script type="text/javascript">
var callback = {
success: function(res) {
var data = YAHOO.lang.JSON.parse(res.responseText);
var homeFolder = "";
var hfIndex = data.homeFolder.indexOf("/User Homes/");
if (hfIndex !== -1) {
homeFolder = data.homeFolder.substr(hfIndex+12);
}
var repoLinks = $("a[title='Repository']");
for (var ii = 0; ii < repoLinks.length; ii++) {
repoLinks.get(ii).href = "/share/page/repository#filter=path|/User%2520Homes/" + homeFolder;
}
}
};
var sUrl = Alfresco.constants.PROXY_URI + "demo/get-home-folder-path";
var postData = "";
var getData = "";
var request = YAHOO.util.Connect.asyncRequest('GET', sUrl+getData, callback, postData);
</script>
There may possibly be a better way, but I was unable to find it. I'll probably refine it later, and this should mostly just be used as a starting point, but I figured I'd post it in case anyone had a similar problem.
Although not super elegant, I guess you can append parameters or anchors using a Javascript onclick handler on the link. Not quite sure which webscript renders the toolbar, but that one may be a good place to put the customization.

embedding sources dynamically

is it possible to embed sources dynamically. instead of doing this
[Embed(source = '../../../../assets/levels/test.xml')]
I could probably do something like this
var src = '../../../../assets/levels/test.xml'
[Embed(source = src )]
It's not possible for anything within metadata annotations to be dynamic :/. That is, you can't place variables into metadata annotations. If that was possible, there would be SO many cool possibilities. So your first option is the only way to directly embed xml.
You could, however, write a custom metadata parser that figured out how to load (not embed) your xml file. Something like:
[LoadFile]
public var source:String = "../../../../assets/levels/test.xml";
I would implement that like the code below (just wrote this right now, haven't tested it). And then you'd "process" your class via something like MyMetadataUtil.process(this). Lots of ways to do that.
public function extractMetadata(target:Object):void
{
var description:XML = flash.utils.describeType(target);
var tag:String = "LoadFile"
var metadata:XMLList = description.accessor.metadata.(#name == tag);
metadata += description.variable.metadata.(#name == tag);
var i:int = 0;
var n:int = metadata.length();
// usually called a 'directive'
// holds values from metadata annotation
var token:Object = {};
for (i; i < n; i++)
{
metadataXML = metadata[i];
token.property = metadataXML.parent().#name;
// token.source = myClass.source;
token.source = target[token.property];
var request:URLRequest = new URLRequest(token.source);
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, loader_completeHandler);
loader.addEventListener(IOErrorEvent.IO_ERROR, loader_ioErrorHandler);
loader.load(request);
}
}
protected function loader_completeHandler(event:Event):void
{
event.currentTarget.removeEventListener(event.type, loader_completeHandler);
trace("SUCCESSFULLY LOADED FILE!");
}
protected function loader_ioErrorHandler(event:Event):void
{
event.currentTarget.removeEventListener(event.type, loader_ioErrorHandler);
}
That stuff would go into some util/manager/processor class. Then anywhere in your code, you could use this:
[LoadFile]
public var source:String = "myFile.xml";
And that could be dynamic. Check out the Swiz Framework for some example source code on how to implement custom metadata processors. Or even better, Openflux's MetaUtil. Once you set that up once, you can do some hardcore stuff in your code. Makes coding fun and fast.
Hope that helps,
Lance
Your use case is basically why I created the ability to add extra frames to Flex SWFs that are treated as late-loaded modules. Instead of embedding your level, stream it in after the main application.
Documentation on -frame is sparse. Sorry! Here's some external stuff, that links back to stuff I wrote and Alex Harui wrote. Good luck!
http://www.richinternet.de/blog/index.cfm?entry=FF295F89-DAD8-CCDC-960413842BC0D478

NVelocity -- #parse with embedded resources

I'm generating emails based off embedded NVelocity templates and would like to do something with dynamically included sections. So my embedded resources are something like this:
DigestMail.vm
_Document.vm
_ActionItem.vm
_Event.vm
My email routine will get a list of objects and will pass each of these along with the proper view to DigestMail.vm:
public struct ItemAndView
{
public string View;
public object Item;
}
private void GenerateWeeklyEmail(INewItems[] newestItems)
{
IList<ItemAndView> itemAndViews = new List<ItemAndView>();
foreach (var item in newestItems)
{
itemAndViews.Add(new ItemAndView
{
View = string.Format("MyAssembly.MailTemplates._{0}.vm", item.GetType().Name),
Item = item
});
}
var context = new Dictionary<string, object>();
context["Recipient"] = _user;
context["Items"] = itemAndViews;
string mailBody = _templater.Merge("MyAssembly.MailTemplates.DigestMail.vm", context);
}
And in my DigestMail.vm template I've got something like this:
#foreach($Item in $Items)
====================================================================
#parse($Item.viewname)
#end
But it's unable to #parse when given the path to an embedded resource like this. Is there any way I can tell it to parse each of these embedded templates?
Hey Jake, is .viewname a property? I'm not seeing you setting it in your code, how about you use the following:
#foreach($Item in $Items)
====================================================================
$Item.viewname
#end
I don't know why you're parsing the $Item.viename rather than just using the above? I'm suggesting this as I've just never needed to parse anything!
Please refer to this post where we've discussed the generation of templates.
Hope this helps!

Resources