I have a complicated workflow for sending marketing emails to customers. There's something like twenty activities that decide who gets what kind of email.
95% of my activities are defined in a binary activity library. I assembled my main activity in visual studio.
For certain types of customer I want to have the activity in (say) step 25a behave differently than what I defined when I built it. We could load the activity from xaml hosted in a database.
One option is to clone the entire workflow for those customers, but that is a lot of code duplication.
Is it possible to override whatever the runtime uses to locate and marshal activities so that if my customer is left handed, one activity in the workflow is substituted instead of what I defined in the IDE?
I'm thinking of how you can override the ViewEngine in mvc to dynamically load ipad views or whatever. Is there something similar for loading activities?
You can't replace the activity in the workflow itself if it is compiled into the assembly. There are several options you can use though:
Use a dynamically loaded activity using the ActivityXamlServices.Load() and as XAML is just XML change the XAML before laoding it.
Use a wrapper activity in your workflow that only loads the actual activity at runtime and uses the WorkflowInvoker to execute it.
Separate the intent from the implementation by using an activity and an extension. The activity only grabs all inputs and the extension and calls a function on it. At runtime you can vary the actual implementation of the workflow extension depending on your needs.
Good news... I have built exactly what you need for this in Microsoft.Activities. For details see WF4 How To Invoke a Child Workflow as XAML and just yesterday I added support for tracking child workflows see Tracking Child Workflow with InvokeWorkflow
Related
What I want to develop....
I am currently developing a SaaS-solution (Symfony2) to build HTML-presentations or better slide shows. Users can log into an administration UI and create presentations. This presentations can be played later. A presentation consists of elements. The elements can be images, texts, videos, pdf and more.
This element types should be encapsulated from the user interface. So extern developers can develop such new modules (element types) with defined interfaces and inject it into the system.
If a new module is finished, we move it to a specific directory in the symfony2 directory and the system detect the new module. No hardcoded-changes in the administration ui system should be neccessary.
Each module has a own "product-number". So we can use a database to enable or disable modules for different users.
What functions must be implemented by a module?
In the administration ui the user has the possibility to create a presentation and add elements of different types (the modules). User sees a timeline with the elements. When he clicks on an element, the editor for this element will be shown under the timeline (Parent-Child-View). Each module has different editors. A text-module needs other configuration-possbilities than an image-module.
So, in admin UI we need functions to edit elements:
createNewElement() creates new entry in the database (module has own tables, e.g. mod_text_elements)
renderEditorView() generates HTML which will be shown in the administration ui with module-specific inputs. E.g. image-upload/crop, WYSIWYG-editor, ...
saveEditorInputs() the module needs to handle the data entered in the editor and save it to the elements entry in the database
deleteElement() to delete an element
The output for the presentation:
Later we want to play this presentation. So a loop goes through the presentation elements and asks the modules of the element what and how to show it.
renderPresentation() to render (HTML) an element for the presentation
Database
I've made a little er-diagram of a possible solution to save the information about modules and elements in a database. The yellow entities are module-specific tables.
How to realize this in Symfony2?
My frist idea is to define an interface which have to be implemented by the modules. But which class has to implement this? Controllers?
Are modules = bundles?
How to realize the View-in-View of the editor? The editor of the module (e.g. renderEditorView()) should be viewed in the user interface of the administration ui.
I'd do it by hooking in to the EventDispatcher Component.
Your 'Master' Controller would define a set of events which correspond to the standard CRUD actions you've defined above ... onCreateNewElement(), onRenderEditorView(), etc. You'll probably find a dozen more to provide hooks for as you build your application (allowing plugins to add tools to a toolbar for example).
You'd define a Service (this doesn't HAVE to be a Controller Class), which looks for new 'modules' and adds their correctly-named methods as listeners for your custom application events.
Are modules = bundles? Well, that's entirely up to you. Are you going to provide a method for users to 'install' new modules specifically for your application? Then what a module needs to look like is entirely up to you. Are you going to slip Composer into the mix and allow modules to be installed that way? Places a couple of constraints on the structure, but still pretty much up to you.
How to realise the View-in-View? Again, that comes down to exactly how you define the interface for your 'Event Plugins' and what kind of access they have to resources like TWIG and YAML config.
The question you're REALLY asking is How do I add functionality to an application without hacking existing code ... and the answer is EventDispatcher. The rest is up to you.
There is another way to expand codebase with custom "modules": Dependency Injection Tags.
It works like this:
You create core of the app, which implements basic functionality and registers compiler pass which handles code extension
Modules can be part of the core app OR moved to external bundles
Each module must be registered in DI container with tag supported by your core app, so can be handled properly (adding menu positions, new element types as in your example)
Symfony DI compiles all services and stuff so all modules are available within app instantly (so you can for example iterate over collection of prepared items without need to dynamically building it)
In my opinion EventDispatcher is better for handling real-time actions, like sending notifications when new entity is created (e.g. controller/service dispatches event, some bundle subscribes it and send notification).
When you want to extend core I would recommend DI tags. Of course you have to build all the core (interfaces and whole architecture) so modules can extend existing services' data, then you only use your services.
Whole Symfony full-stack framework is based od this tags, so there is a lot of existing code to investigate for getting the concept.
Please let me know if it's clear enough what I wrote and what's in Symfony docs. If you need some additional info, I'll try to help.
So I'm working on a project with pretty specific client requirements. The want a document that, once uploaded, is automatically given a custom content model (which I've already made) and then, immediately after upload, allow the user to select aspects to add to it. If the user cancels out of the aspect selection, the document needs to be deleted.
We have a full Maven space setup for alfresco and share development and have our standard-document.xml in alfresco/src/main/resource/alfrescco/extension/model.
The question I have is, where in my share environment do I start working on this process? Would it be best to make a custom dashlet that deals with the upload process, or is there some class or function I can rewire within the Slingshot/Spring Application Context. I couldn't find any existing plugins or share amp files that I could use as a reference. Is there anything out there that currently has something similar to this functionality?
I guess you're using Alfresco's Share client, right?
you'll have to have to tweak Share's JavaScript components:
add a custom flag to "metadataRefresh" event object that is fired in x-upload.js
tweak handling of "metadataRefresh" event in documentlist.js to call the relevant action
it's gonna be a though JavaScript implementation task.
Is that possible to trigger the workflow manually?
Say for example that I don't want to trigger the workflow when I save and close my component, but I want to update the component multiple times and, after I feel I am OK, I want to trigger the workflow attached for component.
Like Jeremy said it's not possible (yet), but it would also spoil the whole idea of Workflow that is - you can't have unapproved content checked in. In your case, you can edit component as many times as you want. No matter if you just save it or save and close. It will pass on to the next activity in workflow as soon as you will report "i'm done" - that is finish your activity.
You have to understand a few things about Tridion workflow. It is not designed or intended to be a process workflow, it's an approval workflow.
When changes are done to items that require workflow, workflow starts (item is locked). When you're done with the changes, you finish your activity and move on along the workflow process.
From the sound of it, you're probably working for an organization where workflow drives content publishing, while Tridion was designed from the ground up to not require workflow to publish to a website, workflow is simply for organizations requiring additional validation steps (some would say it's because they can't trust the editors, but that's a different story, which is easier to solve with permissions than workflow, but I digress).
Anyway, the good news for you is that the Workflow engine is being re-designed as we speak, and the next release will bring a lot of new process-oriented concepts into our workflow engine. But currently, what you want to do is not possible.
No, this is not possible. Workflow can only be triggered on the Save of an item. For the situation you mention you simply need to finish the initial activity at the point you are satisfied with the content.
Every tutorial/example i can find for meteor shows a single view application. I would like to build something a little more complex. I'm unclear how to approach multiple views...preferably in a way that's somewhat scalable?
The iron-router package lets you access different views (layouts) by nice, REST-ful human-friendly clean URLs. It supports parameters in the URL, "loading" templates, waiting for subscriptions to finish loading, before and after hooks etc.
At this point you can only create Single Page applications with Meteor. Note that Single Page, doesn't mean you can't have several views - use iron-router for that.
But by design, Meteor serves a big fat unique JavaScript/HTML/CSS application down to the browser, though there's a feature request to allow incremental loading. It is then up to the application (or more precisely, the JavaScript framework), to dynamically render its views in order to display different "pages".
I was wondering the same thing and it took me way too much time getting something started. I finally got a paged app working solidly by using Backbone views and routes, so I created a simple boilerplate project to make setting up an app like this easier in the future.
Live demo here: backbone-boilerplate.meteor.com
Source code here: github.com/justinmc/meteor-backbone-boilerplate
Have you looked at madewith.meteor.com?
A bunch of apps there have multiple views using Backbone also Jonathan Kingston who created britto has started simple meteor framework called Stellar
At this stage of the game not sure if there really are best practices. But these two seem to be the current flow.
You can also make a tabbed interface for multiple views. There is a package project "Smart package for generating a tabbed interface with pushState" github project here: https://github.com/possibilities/meteor-tabs
The best solution right now is using a routing package (router is basic but works). The workflow is something like this:
declare routes; return a template name for each route
place the reactive helper provided by the package in your body tag
the reactive helper will return the template associated to that route
you create a template for each route and optionally set custom publish functions
Router will give you browser history (client side).
Note that at this time there are some limitation on the way Meteor handles html/js. They are load all at the same time. The bright side is that once the app is loaded, page transitions will be instant.
I'm playing several video streams in my flex application. Plus there are sounds of application UI. Is there possibility to mute entire application or I should silence each of potential sound sources?
Have you tried
SoundMixer.soundTransform = new SoundTransform(0, 0);
I'm pretty sure there is no way to do that with ActionScript out of the box. You'll need to have some manager class that keeps track of all the sounds (Sound, SoundChannel, SoundTransform, etc and your video streams) in your application and that has logic for muting.
If you can force your users to use firefox, there is a plugin available to mute swf files. Mute Flash - https://addons.mozilla.org/en-US/firefox/addon/5453
You probably have to re implement your app to centralize the control of audio components within your app. There is a design pattern out there called Inversion of Control that may be useful for this problem.
http://en.wikipedia.org/wiki/Inversion_of_control
Specifically with Flex, you should lookup the Model Locator pattern with Cairngorm.
http://www.adobe.com/devnet/flex/articles/cairngorm_pt2_06.html
You could use this to store all the various audio levels for your application in a single location. And you could add a method called muteAll() that would go in and set all the levels to 0. Anytime you create a new audio component in the app make sure to add a reference to its volume level in the model locator. Bind the audio's volume level to the value set in the model locator. Then elsewhere in the app you can change the value in the model locator and through binding the audio component you build will get updated.
This might also be helpful.
http://livedocs.adobe.com/flex/3/html/help.html?content=Working_with_Sound_23.html#160274