In Tridion 2011 SP1, Event System, I'm trying to get the WorkItem of an object that I know is in workflow, but I don't know in whose WorkList it might be.
Scenario Description:
Page must remain locked while a given component is in workflow
If component workflow state changes, page state should change too
What I thought of doing was an Event triggered on FinishActivityEventArgs, which would:
Check if current item is Component
Get the corresponding page (GetUsingItems of type page)
Check if the page is also in workflow
Get the page in question
Get the WorkItem for the page
Finish the current activity and pass on the corresponding activity details
I am about ready with most steps but having doubts on step 5. The only method I see so far to get the WorkItems is using session.WorkflowManager.GetUserWorkItems(userWorkItemsFilter) but this will probably fail if the page is not in the current user's work items, right?
Any tips/directions?
I believe you will need to use the session.WorkflowManager.GetListProcesses method to find all the processes, rather than just the ones for the current user. I imagine you may need to impersonateate as an Administrator in order to get all the items back though.
Related
I have this unique requirement where each time a particular Content Fragment is updated in AEM, all the Experience Fragments referencing that particular Content Fragment need to be automatically exported to Adobe Target.
Thinking about using SQL2 query to retrieve XFs referencing a particular CF and then incorporating this into a workflow process. Also, wondering if I can leverage aem OOTB workflow process called "Export to Target" in this.
Not really sure of how to call this "Export to Target" process on each Experience Fragment that we need to export to Target or is this possible at all?
Wondering if anyone has ever come across this requirement and succeeded.
Highly appreciate any tips or suggestions in this regard. Many Thanks in advance.
Whenever a Content Fragment is created or updated an OSGi event is triggered. All events are logged under http://localhost:4502/system/console/events. You could write a EventListener or EventHandler, get the path of the event, get the Resource and adapt it to com.adobe.cq.dam.cfm.ContentFragment. The topic for these events is "com/day/cq/dam" or in this constant.
From the adapted Class or Resource you can get informations about the model and if it's the model you want to process.
To find all references I would also create an oak index and use SQL2 query to find all references.
The query would be something like this:
select [jcr:path], [jcr:score], * from [nt:base] as a where contains(*, '"/content/dam/myReferencedModel"')
If you have all referencing XF's you can kick off any workflow via WorkflowService:
#Reference
private WorkflowService workflowService;
WorkflowSession wfSession = workflowService.getWorkflowSession(session);
WorkflowModel wfModel = wfSession.getModel("/var/workflow/models/mymodel");
WorkflowData wfData = wfSession.newWorkflowData("JCR_PATH", "/payload");
wfSession.startWorkflow(wfModel, wfData);
I have a task to export a repeat grid's content to Excel. I have read an
article, but I still can't realize how to properly use it. I tried to repeat article's steps to provide pzRDExportWrapper, but after I click "Save" button I get the error:
Method: Rule-Obj-Activity instance not found:
Sb-FW-CTrackFW-Work.pzRDExportWrapper. Details: Invalid value for
Activity name passed to ActivityAssembler.
Could anybody give me any suggestions? Thank you.
You invoke activity from another activity which applies to class Sb-FW-CTrackFW-Work. Rule Resolution use primary context Sb-FW-CTrackFW-Work class and try invoke activity pzRDExportWrapper from it and you get error (because rule resolution can't found invoked activity in this class).
Activity pzRDExportWrapper applies to Rule-Obj-Report-Definition class. Try invoke from it.
Try activity step as below:
Call Rule-Obj-Report-Definition.pzRDExportWrapper
Or use step page for this step which defined as applies to Rule-Obj-Report-Definition class(you can declare it on Pages&Classes tab)
Okay. I have resolved the issue (thank you njc). I have two sections on a lone web page.
A context of the first section is my custom data page Co-Name-FW-Data-Search. The Search page has some single value properties which are initialized by an user via an UI.
The second section is a repeat grid section, a report definition as a source. My Search page pointed out in a Pages and Classes tab. Also there is a Page, which is created by report definition and contains results. The report definition takes Search’s values as parameters.
So, I have created an activity and passed the Search page and a Cods-Pega-List MyResultList as parameters. There are some steps in the activity:
Check if Search is null. If true- skip step; else - transfer Search properties into Params props with Data Transform.
Set Param.exportmode = "excel"
Call pzRDExportWrapper with Step Page MyResultList.pyReportDefinition. Pass current parameter page.
P.S.: If it doesn’t work try to play with report definition’s settings.
P.P.S.: An only minus of pzExportWrapper is that it invokes report definition again.
I am totally new to classes and OOP, so please bear with me.
I am creating a large scale web app which I'm trying to keep tidy by creating my own classes.
For instance I have a Public Class Product which has several properties. One way I am using it is on page load a product ID is assigned to the ID property which in turn gets the details for that product and assigns the various data to the other properties. So within my code I can used for example product.price or product.description and get the appropriate values. This has worked fine, but I found that because the class was initiated on page load it was getting the data from the DB each time that the page refreshed. I stopped this by using an If Not IsPostback to initiate the class. This meant that the data was pulled in only on the initial page load. So far so good.
I then needed to compare a value in a textbox with a property of the product. I have a textchanged event with
If textbox1.Text <> product.description Then....
but here I get a wavy line under product.description and VS2010 is saying that the object is not defined. Its Dim'd in the page.load so I moved the Dim statement outside the page class so that it will be accessible to all events on the page.
The dim statement is Dim product as New product
In my not ispostback chunk of code I have for example product.ID = 1 which will get all the product properties for product 1
The wavy line has gone but when I run the page all works fine on page load. Data is displayed so my product class is working fine. As soon as I make a change in textbox1 and the event triggers product.description is nothing. It got reinitalised.
How do I stop this from happening...
Your "Product" is not persisted between postbacks.
Only control objects in aspx page are persisted/restored automatically.
To remedy this there are multiple approaches.
If Product is loaded via setting "Product.id=1" then what I woudl do is have a hiddenfield that receives the value of the product.id during prerender event (to save it in the page) and in an init event I would restore the "Product.id=hiddenfield.value" but only when it is a postback to reload your object.
EDIT
Thanks for picking my answer. I'll elaborate a little on the various ways to deal with this and why I suggested my answer.
Store Key in HiddenField Reload from DB:
PROS: Product is always Fresh/Correct/Current values. Corresponding to the database. Databases are very efficient to return a record based on a primary key. Very little data is sent to and posted back from the client browser. Low complexity. Each page opened by the client is safely isolated.
CONS: Multiple database transactions. If the DB is already strained or extremely massive you may need to consider even the smallest efficiency gain, but this is not common or likely on a primary key based record
Session State (store entire object):
PROS: Lowest time to "load" object since it's available in memory already once loaded. Less DB Transactions. No data piggy backed to the client and back again.
CONS: Object can become "out-of-date" if altered in the DB. Users who open multiple pages of your application can end up getting the wrong object if both require a different "Product", so instead to be totally safe you need a more complex structure in place to store more then one product or store them based on some kind of key (such as the product ID). Server Memory is used, if serving thousands of users or your product data is large it can become an issue, especially if you do this in many pages with many objects.
Serialization (store the entire object in the page in a field, similar to event state):
PROS: Once loaded, the Database is accessed only once for a specific product, then the product is held, in it's entirety inside the page, it is recreated by the server from the data in the field or via viewstate. Each page opened by the client is safely isolated. Is fairly easy to implement storing in ViewState of the Page.
CONS: Object can become "out-of-date" if altered in the DB. ALLOT more data is added to your page responce and the users next page request. Is more complex to implement because the object needs to be designed to be serialized correctly. Complex objects require allot of manual code to be serialized successfully.
again, there are many other ways to deal with this, such as storing items in a synclocked dictionary style object global to the application, but is considerablby more and more complex as you go.
This is likely the standard ASP.NET page life cycle problem.
After you initialize the page, it gets sent to the user's browser. When the user clicks on something, the browser sends a postback request back to your application. The view state allows the textbox1 object to remember what was in its Text property. However, your Page_Load ran from scratch, and, yes, everything including your product object got recreated from scratch.
If you want your product object to "remember" what it knew before the postback, you'll have to remind it. One way would be to store the initialized value in Session state, and then refresh your product object during the postback section of the Page_Load method.
Every time you do a postback, you're working with a new instance of your page class. The prior copy of your class was thrown away and probably disposed before your browser even rendered the page to the screen.
If you want to persist a value across http requests (of which postbacks are just one type), then you need to put it somewhere like the Session.
I will try to be as concise as possible. I'm using Flex/Hibernate technologies for my app. I also use Cairngorm micro-architecture for Flex. Because i'm beginner, i have probably misunderstand something about Caringorm's ModelLocator purpose. I have following problem...
Suppose that we have next data model:
USER ----------------> TOPIC -------------> COMMENT
1 M 1 M
User can start many topics, topics can have many comments etc. It is pretty simple model, just for example. In hibernate, i use EAGER fetching strategy for unidirectional USER->TOPIC and TOPIC->COMMENT relations(here is no question about best practices etc, this is just example of problem).
My ModelLocator looks like this:
...
public class ModelLocator ....
{
//private instance, private constructor, getInstance() etc...
...
//app state
public var users:ArrayCollection;
public var selectedUser:UserVO;
public var selectedTopic:TopicVO;
}
Because i use eager fetching, i can 'walk' through all object graph on my Flex client without hitting the database. This is ok as long as i don't need to insert, update, or delete some of the domain instances. But when that comes, problems with synchronization arise.
For example, if i want to show details about some user from some UserListView, when user(actor) select that user in list, i will take selected index in UserList, get element from users ArrayCollection in ModelLocator at selected index and show details about selected user.
When i want to insert new User, ok, I will save that user in database and in IResponder result method i will add that user in ModelLocator.users ArrayCollection.
But, when i want to add new topic for some user, if i still want to use convenience of EAGER fetching, i need to reload user list again... And to add topic to selected user... And if user is in some other location(indirectly), i need to insert topic there also.
Update is even worst. In that case i need to write even some logic...
My question: is this good way of using ModelLocator in Cairngorm? It seems to me that, because of mentioned, EAGER fetching is somehow pointless. In case of using EAGER fetching, synchronization on Flex client can become big problem. Should I always hit database in order to manipulate with my domain model?
EDIT:
It seems that i didn't make myself clear enough. Excuse me for that.
Ok, i use Spring in technology stack also and DTO(DVO) pattern with flex/spring (de)serializer, but i just wanted to stay out of that because i'm trying to point out how do you stay synchronized with database state in your flex app. I don't even mention multi-user scenario and poling/pushing topic which is, maybe, my solution because i use standard request-response mechanism. I didn't provide some concrete code, because this seems conceptual problem for me, and i use standard Cairngorm terms in order to explain pseudo-names which i use for class names, var names etc.
I'll try to 'simplify' again: you have flex client for administration of above mentioned domain(CRUD for each of domain classes), you have ListOfUsersView(shows list of users with basic infos about them), UserDetailsView(shows user details and list of user topics with delete option for each of topic), InsertNewUserTopicView(form to insert new topic) etc.
Each of view which displays some infos is synchronized with ModelLocator state variables, for example:
ListOfUsersView ------binded to------> users:ArrayCollection in ModelLocator
UserDetailsView ------binded to------> selectedUser:UserVO in ModelLocator
etc.
View state transition look like this:
ListOfUsersView----detailsClick---->UserDetailsView---insertTopic--->InsertTopicView
So when i click on "Details" button in ListOfUsersView, in my logic, i get index of selected row in ListOfUsers, after that i take UserVO object from users:ArrayCollection in ModelLocator at mentioned index, after that i set that UserVO object as selectedUser:UserVO in ModelLocator and after that i change view state to UserDetailsView(it shows user details and selectedUser.topics) which is synchronized with selectedUser:UserVO in ModelLocator.
Now, i click "Insert new topic" button on UserDetailsView which results in InsertTopicView form. I enter some data, click "Save topic"(after successful save, UserDetailsView is shown again) and problem arise.
Because of my EAGER-ly fetched objects, i didn't hit the database in mentioned transitions and because of that there are two places for which i need to be concerned when insert new topic for selected user: one is instance of selectedUser object in users:ArrayCollection (because my logic select users from that collection and shows them in UserDetailsView), and second is selectedUser:UserVO(in order to sync UserDetailsView which comes after successfull save operation).
So, again my question arises... Should i hit database in every transition, should i reload users:ArrayCollection and selectedUser:UserVO after save in order to synchronize database state with flex client, should i take saved topic and on client side, without hitting the database, programmatically pass all places which i need to update or...?
It seems to me that EAGER-ly fetched object with their associations is not good idea. Am i wrong?
Or, to 'simplify' :) again, what should you do in the mentioned scenario? So, you need to handle click on "Save topic" button, and now what...?
Again, i really try to explain this as plastic as possible because i'm confused with this. So, please forgive me for my long post.
From my point of view the point isn't in fetching mode itself but in client/server interaction. From my previous experience with it I've finally found some disadvantages of using pure domain objects (especially with eager fetching) for client/server interaction:
You have to pass all the child collections maybe without necessity to use them on a client side. In your case it is very likely you'll display topics and comments not for all users you get from server. The most like situation you need to display user list then display topics for one of the selected users and then comments for one of the selected topics. But in current implementation you receive all the topics and comments even if they are not needed to display. It is very possible you'll receive all your DB in a single query.
Another problem is it can be very insecure to get all the user data (or some other data) with all fields (emails, addresses, passwords, credit card numbers etc).
I think there can be other reasons not to use pure domain objects especially with eager fetching.
I suggest you to introduce some Mapper (or Assembler) layer to convert your domain objects to Data Transfer Objects aka DTO. So every query to your service layer will receive data from your DAO or Active Record and then convert it to corresponding DTO using corresponding Mapper. So you can get user list without private data and query some additional user details with a separate query.
On a client side you can use these DTOs directly or convert them into client domain objects. You can do it in your Cairngorm responders.
This way you can avoid a lot of your client side problems which you described.
For a Mapper layer you can use Dozer library or create your own lightweight mappers.
Hope this helps!
EDIT
What about your details I'd prefer to get user list with necessary displayable fields like first name and last name (to display in list). Say a list of SimpleUserRepresentationDTO.
Then if user requests user details for editing you request UserDetailsDTO for that user and fill tour selectedUser fields in model with it. The same is for topics.
The only problem is displaying list of users after user details editing. You can:
Request the whole list again. The advantage is you can display changes performed by other users. But if the list is too long it can be very ineffective to query all the users each time even if they are SimpleUserRepresentationDTO with minimal data.
When you get success from server on user details saving you can find corresponding user in model's user list and replace changed details there.
Tell you the truth, there's no good way of using Cairngorm. It's a crap framework.
I'm not too sure exactly what you mean by eager fetching (or what exactly is your problem), but whatever it is, it's still a request/response kind of deal and this shouldn't be a problem per say unless you're not doing something right; in which case I can't see your code.
As for frameworks, I recommend you look at RobotLegs or Parsley.
Look at the "dpHibernate" project. It implements "lazy loading" on the Flex client.
Assume you have a page in ASP.NET where it makes sense to use JavaScript/jQuery to modify the DOM with values that will eventually be read by the server on submit. For example, you have a form that allows end users to add/remove objects (like dependents on a health insurance form or assets on a loan application).
What are some ways to ensure that these items are detected and retrieved by the server once the information is submitted?
I've tried a few things that work, but none of them seem perfect so I wanted to see what the community had to offer.
Also, I'm not looking for suggestions that avoid dynamic DOM elements (like use a Wizard, etc.). I'm specifically trying to improve my technique with dynamically created DOM elements.
There are two ways to do something like this:
First: post only the information on submit. As long as you add both a name and an id attribute to every element in your DOM, every element is represented in Request.Form, so you can easily iterate through this collection.
I tend to have a naming convention like insurance_row_1, insurance_row_2 and so forth. You can find all rows like Request.Form.AllKeys.Where(k=>k.StartsWith("insurance_row_")).
When you want to save every action on the server:
Maintain a state container in javascript, that holds information in some dictionary-like control, where you put every action that has been performed by your application, and a state whether the server has processed them. Something like:
var stateContainer = [
{ 'put-insurance-row-1', false },
{ 'delete-insurance-row-1', false }
];
Do an AJAX request to the server to perform such an action, and use the state-container's key to track whether the request succeeded or failed. Set the state to 'true' when the request has been successfully submitted. Make sure to do this in order in which you receive the events, so send them one-by-one to the server to ensure that you keep a valid state.
You can (try) to prevent closing the browser if some states aren't persisted yet.
why are you using client side code to do this? i would go the route of doing a postback and adding a control from server side code. the built in ajax updatepanel should handle this very quickly.