What is ATG pipelines and how does it works? - atg

I have some idea on atg droplets, dsp tags and writing custom droplets. I would like to know about pipelines on ATG topics. When I trying to refer oracle documentation for this I'm getting bit confused with understanding what it is and working flow of it. Can I create one custom pipeline manager which executes my custom processors sequentially.If possible how can I do this?? How to trigger my pipeline manager from my jsp page. Please guide me some tutorials or online documents for best learning for pipelines.
Code snippets is highly preferable.
Thanks in advance

A pipeline is an execution mechanism that allows for modular code execution. Oracle ATG Web Commerce uses pipelines to execute tasks such as loading, saving, and checking out Orders .The PipelineManager implements the pipeline execution mechanism.
There are two request-handling pipelines used by Dynamo.
• DAF Servlet Pipeline - It is used to handle the JSP request.
• DAS Servlet pipeline - It is used to handle JHTML request. Because JHTML is a proprietary language, it relies on the page compiler provided in the DAS servlet pipeline to generate JHTML into a servlet that’s rendered as HTML by the application server.
And also there is something called commercePipeline which takes care of order processing.
Request-Handling pipelines and commerce pipelines works in different ways.
DAS/DAF(ie., request pipelines)
It's a configuration defined with a series of servlets executed in a sequence on basis of each servlet's output. One of Dynamo's most important tasks is handling HTTP requests. In handling these requests, Dynamo uses session tracking, page compilation, Java Server Pages, and other powerful extensions to the basic Web server model.Request handling can usually be broken down into a series of independent steps. Each step may depend on additional information being available about the request, so order does matter. However, the individual steps are separable. For example, a typical request might go through these steps:
1) Compare the request URI against a list of restricted directories, to make sure that the user has permission to access the specified directory.
2) Translate the request URI into a real file name, taking "index" files into account when the file name refers to a directory.
3) Given the file name's extension, determine the MIME type of the file.
4) From the MIME type, dispatch the request to the appropriate handler.
So DAF/DAS pipelines comes into picture when there is a request. In atg_bootstrap.war web.xml has the information about the server startup.
When the server starts NucleusServlet.java gets loaded in the app server. This class initializes nucleus and other components and then adds all of them to nucleus namespace. And when a web application is accessed (DynAdmin,CRS,MotopriseJSP), nucleus routes the flow to either daf/das pipeline. If the application MIME type is Jhtml then das pipeline processes the request further. It is routed to DynamoProxyServlet class where it does the further processing by calling list of servlets. And if it is .jsp then Daf pipeline handles the further requests by calling PageFilter class.The reason for using a filter but not a servlet to invoke DAF pipeline is:
JSP pages and fragments are handled by the application server meaning that JBoss, WebLogic , WebSphere is the one responsible for compiling and executing the resulting page code. The best way to hook into this process is by using a Filter. For JHTML pages, that's a different story since the app server (not all app servers)can't parse and compile the pages. A servlet is used to redirect the request down the DAS pipeline where the page can parsed and executed by the ATG page compilationmechanism.
In case of Commerce Pipeline:
Pipeline Manager implements commerce pipeline functionality by reading a pipeline definition file ie., commercepipeline.xml. When application is deployed ,Nucleus initializes pricing engine, where OrderManager initializes pipelineManager. OrderManager.processOrder method invokes the pipeline chains in commercepipeline.xm. A pipeline chain would have processors which are simple java classes doing small operations .This xml can be extended by adding a custom processor. But in cases where a single processor need to be called, call runProcess method of pipelineManger by passing processorchaninId .
Extending DAF/DAS pipeline and commerce pipeline are not same
we can create our own custom servlets to put it in DAF/DAS pipeline .
extend you own servlet class wither with PipelineableServletImpl or InsertableServletImpl
and re-write the service method depending on what you want to do.Further details are widely available on the internet :)
and coming to commerce pipeline
Commerce pipeline is defined in an xml file located in /B2CCommerce/config/atg/commerce/commercepipeline.xml.PipeLine manager is responsible load the pipeline definition xml and initialize the pipeline chains. Write your processor class. Custom Processor class should be an implementation of PipelineProcessor.
extend your own class by PipelineProcessor and re-write runProcess method.You also have to create respective .properties file for your processor.And then in
B2CCommerce/config/atg/commerce/commercepipeline.xml
<pipelinechain name=" lastExistingchain" transaction="TX_REQUIRED" headlink=" lastExistinglink">
……..
<transition returnvalue="1" link=" sampleDemoLink"/>
</pipelinelink>
<pipelinelink name="sampleDemoLink" transaction="TX_REQUIRED">
<processor jndi="demo/atg/order/processor/MyProcessor"/>
</pipelinelink>
</pipelinechain>
restart ATG server.
Coming to you other question that if we can create our own pipeline manager
Answer is yes.
Just create /atg/registry/PipelineRegistry/ .properties file in your local config folder.PipelineRegistry is a service where all pipeline managers are registered
this service has property called pipelineManagers just append your pipeline manager component to this property.if you want to use existing commercePipelineManager class but with different bunch of processors executing one aftr the other.create a definition xml file which looks something like this
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE pipelinemanager
PUBLIC "-//Art Technology Group, Inc.//DTD Dynamo Pipeline Manager//EN"
'http://www.atg.com/dtds/pipelinemanager/pipelinemanager_1.0.dtd'>
<pipelinemanager>
<!-- This chain updates (saves) an Order to the repository -->
<pipelinechain name="updateOrder" transaction="TX_REQUIRED" headlink="updateOrderObject">
<pipelinelink name="updateOrderObject" transaction="TX_MANDATORY">
<processor jndi="/atg/commerce/order/processor/SaveOrderObject"/>
<transition returnvalue="1" link="updateCommerceItemObjects"/>
</pipelinelink>
<pipelinelink name="updateCommerceItemObjects" transaction="TX_MANDATORY">
<processor jndi="/atg/commerce/order/processor/SaveCommerceItemObjects"/>
<transition returnvalue="1" link="updateShippingGroupObjects"/>
</pipelinelink>
<pipelinelink name="updateShippingGroupObjects" transaction="TX_MANDATORY">
<processor jndi="/atg/commerce/order/processor/SaveShippingGroupObjects"/>
<transition returnvalue="1" link="updateHandlingInstructionObjects"/>
</pipelinelink>
<pipelinelink name="updateHandlingInstructionObjects" transaction="TX_MANDATORY">
.......
.......
<pipelinechain name="rejectQuote" transaction="TX_REQUIRED" headlink="quoteRejection">
<pipelinelink name="quoteRejection" transaction="TX_MANDATORY">
<processor jndi="/atg/commerce/order/processor/RejectQuote"/>
</pipelinelink>
</pipelinechain>
<!-- This pipeline chain should be called when a requested quote is to be completed -->
<pipelinechain name="completeQuote" transaction="TX_REQUIRED" headlink="completeQuoteRequest">
<pipelinelink name="completeQuoteRequest" transaction="TX_MANDATORY">
<!-- this is a dummy processor that should be extended to save quote details -->
<processor jndi="/atg/commerce/order/processor/CompleteQuoteRequest"/>
</pipelinelink>
</pipelinechain>
</pipelinemanager>
here you can mention your custom processors.
As you have registered your new pipelinemanager in pipeline registry.It gets automatically initialized.So if you do any operation in JSP related to your pipeline,in background all the processing gets done.

There are two entirely separate things in ATG commonly known as pipelines.
They are not at all related to one another.
1. The Servlet Pipeline
This is a chain of servlets through which all requests pass before hitting your custom code (JSP page, Form Handler, Droplet or anything else). The purpose of this pipeline is to decorate the incoming request to provide the request with the context that the ATG framework needs to, for example, associate the request to a Dynamo Session and to load a User Profile. The DAS module defines the basic servlet pipeline and various modules add additional servlets into it.
You modify this pipeline by changing the nextServlet or related properties of existing components, and by creating Nucleus components that are instances of classes extended from PipelineableServlet
You would choose to customise this if you wanted to perform an action or make a decision on each incoming request - somewhat similar to what you would use Filters in standard J2EE web applications or Interceptors in a Spring MVC application.
You can see what is defined in your servlet pipeline by looking the /atg/dynamo/servlet/dafpipeline/DynamoHandler component in the Dynamo Admin interface.
2. Processor Chains
A processor chain is a way of executing discreet processes and linking them together based on the outcome (resulting status code) of each process. There is a component in the Nucleus called the Pipeline Manager which holds the configuration of each Processor Chain defined in the system, and manages the execution of these chains.
Processor chains are used by the Commerce module to manage, for example, the creation of an order to ensure referential integrity between all the constituent parts. This is sometimes called The Commerce Pipeline.
Processor chains are conceptually more related to scenarios, and completely unrelated to the servlet pipeline.
You modify a processor chain by creating or editing the XML file that defines the chain. You create new processors by creating a Nucleus component from a class that implements the PipelineProcessor interface.
You can see which chains are defined by looking at the PipelineManager component in the Dynamo admin interface. There is also a graphical Pipeline Editor in the ACC.
You would modify an existing pipeline chain if you want to add or remove a step in it.
You would create a new chain if you wanted to split a long and complex process - usually repository operations - into multiple discrete steps to be sequenced together by an externalised process flow.

Related

How to bind different transport configs to datareader in OpenDDS

can different transport(shmem, tcp) bind to different datawriter/datareader in one publisher/subscriber in OpenDDS?
I'm not sure OpenDDS supports this way with RepoInfo Discovery or only in Static Discovery?
I use
`
TheTransportRegistry->bind_config("tcp1", datawriter1);
TheTransportRegistry->bind_config("shmem1", datawriter2);
`
but it seems not work. still use the publisher‘s transport config
Yes, it should be possible, but it needs a bit more setup. After they are created writers and readers (as well as any DDS::Entity) have an enable function that has to be called before they can be used. By default this is called automatically by create_datawriter and create_datareader. This is important because readers and writers can't change their config after they're enabled. You have to disable the autoenable_created_entities property in parent entity's QoS, create the reader or writer, call bin_config, and finally call enable manually. Section 3.2.16 of the OpenDDS Developer's Guide talks a bit about this, but doesn't have an example, so here's snippet that I tested with the error checks and unrelated args omitted:
DDS::PublisherQos pub_qos;
participant->get_default_publisher_qos(pub_qos);
pub_qos.entity_factory.autoenable_created_entities = false;
DDS::Publisher_var publisher =
participant->create_publisher(pub_qos, /*...*/);
DDS::DataWriter_var datawriter1 = publisher->create_datawriter(/*...*/);
TheTransportRegistry->bind_config("tcp1", datawriter1);
datawriter1->enable();
You can also set this QoS on the domain participant or the service participant instead of the publisher or subscriber, but that requires manually enabling all the entities, which includes the publishers, subscribers, and topics, so I'm not sure I recommend that.

How to set up API gateway without specifying all resources

I have some EC 2 applications (in node.js) that have many REST paths, and since still in development process, the path keep changing.
How can I set up in the api-gateway, that will map to multiple paths, instead of specify each of them?
e.g.
my ec2 end points have:
my.ec2.com/api/test
my.ec2.com/api/test1
my.ec2.com/api/test2
my.ec2.com/api/user/time
my.ec2.com/api/user/time1
my.ec2.com/api/user/time2
instead of setting the all resources in api-gateway,
can I do something like:
api-gateway.amazon.com/api that points to my.ec2.com/api/
and it will resolve any call to http://api-gateway.amazon.com/api/test automatically points to http://my.ec2.com/api/test, etc. ?
As of today, it is still impossible in the API gateway console.
The solution is to use Swagger. then I can use some scripts to generate the Swagger file and import to API gateway. In fact, it is a good solution because I can source control on Swagger.

Alternate way of configuring data sources in quartz scheduler properties file

We are configuring the Quartz Scheduler data sources as specified in the documentation that is by providing all the details without encrypting the data base details. By this the data base details are exposed to the other users and any one who have access to the file system can easily get hands on.
So are there any other ways to provide the data sources details using API or provide the database details by encrypting and providing the details as part of quartz.properties file
On class "StdSchedulerFactory" you can call the method "initialize(Properties props)" to set needed propertries by API. Then you don't need a property-file. (See: StdSchedulerFactory API)
Example:
public Scheduler createSchedulerWithProperties(Properties props)
throws SchedulerException {
StdSchedulerFactory factory = new StdSchedulerFactory(props);
return factory.getScheduler();
}
But then you have to set all properties of SchedulerFactory. Also the properties, that have a default value with default constructor. (Search for 'quartz.properties' inside of 'quartz-2.2.X.jar' to get default property values of quartz.)

WCS7 best practice to receive certain catalog entry information?

[WCS 7, FixPack 7, Feature Pack 6]
I need to generate a feed with certain catalog entry (product) information such as name, image(s), category, price, seo-url, descriptive attributes and so on.
To generate this feed i will use the scheduler framework and created a controller command which will be invoked after a certain time has passed.
Now i need to receive the catalog entry data of each item in a specific store/catalog.
As far as i know there are several ways to achieve this:
Access Beans
SOA (new Access Profile with specific SQL)
I tried to use Access Beans to get all necessary information but I got stuck with seo-url, price etc.
Are there more ways and what is the best practice to get a specific set of catalog entry attributes?
I suggest you study/investigate in your WCS Development environment how site map generation schedule command is implemented (SitemapGenerateCmd) and how it is calling the JSP template file (sitemap.jsp)
you need to modify a bit in your command to create a jsp template for your feed and call that template from your scheduler command you've created .
calling template command for messaging system, make sure to use following properties in ActionForward tag to register the JSP for messaging from back-end:
example:
<forward className="com.ibm.commerce.struts.ECActionForward"
name="SitemapIndexView" path="/SitemapIndex.jsp">
<set-property property="direct" value="true"/>
<set-property property="resourceClassName" value="com.ibm.commerce.messaging.viewcommands.MessagingViewCommandImpl"/>
<set-property property="interfaceName" value="com.ibm.commerce.messaging.viewcommands.MessagingViewCommand"/>
<set-property property="properties" value="storeDir=no"/>
<set-property property="implClassName" value="com.ibm.commerce.messaging.viewcommands.MessagingViewCommandImpl"/>
</forward>
then the logic for extracting data from your product/catalog beans will be handled inside the JSP and you can easily form the output data as you want (XML, CSV, JSON .. etc)
the advantages and benefits of using this way are you can leverage Commerce Server OOTB JSTL tags , WCF tags for retrieving all information and using wcf:url for SEO URLS OOTB even you can call BOD/SOA commands using <wcf:getData tag and finally your will get more structured design that can easily maintain and reuse in future .
sitemap.jsp is a good resource for you how to iterate through catalog and sub-catalog to extract product info.
hope that those help you find your solution. need some search and understanding of existing sitemap generation utility .
Thanks.
Abed

Creating a REST service in Sitecore

I'm trying to build a REST service in a Sitecore root. My application start looks like this:
void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = System.Web.Http.RouteParameter.Optional });
}
And my URL looks like this:
http://{mydomain}/api/books
I have the correct controller and all that.
But Sitecore keeps redirecting me to the 404 page. I've added the path to the IgnoreUrlPrefixes node in the web.config, but to no avail. If I had to guess, I'd think that Sitecore's handler is redirecting before my code gets the chance to execute, but I really don't know.
Does anybody have any idea what might be wrong?
Your assessment is correct. You need a processor in the httpRequestBegin pipeline to abort Sitecore's processing. See the SystemWebRoutingResolver in this answer:
Sitecore and ASP.net MVC
It's also described in this article:
http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2010/10/Sitecore-MVC-Crash-Course.aspx
But I'll include the code here as well. :)
public class SystemWebRoutingResolver : Sitecore.Pipelines.HttpRequest.HttpRequestProcessor
{
public override void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
{
RouteData routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(args.Context));
if (routeData != null)
{
args.AbortPipeline();
}
}
}
Then in your httpRequestBegin configuration:
<processor type="My.SystemWebRoutingResolver, My.Classes" />
You might want to have a look at Sitecore Web Api
It's pretty much the same you are building.
Another option, which I've used to good effect, is to use the content tree, the "star" item, and a sublayout/layout combination dedicated to this purpose:
[siteroot]/API/*/*/*/*/*/*/*/*/*
The above path allows you to have anywhere between 1 and 9 segments - if you need more than that, you probably need to rethink your process, IMO. This also retains all of the Sitecore context. Sitecore, when unable to find an item in a folder, attempts to look for the catch-all star item and if present, it renders that item instead of returning a 404.
There are a few ways to go about doing the restful methods and the sublayout (or sublayouts if you want to segregate them by depth to simplify parsing).
You can choose to follow the general "standard" and use GET, PUT, and POST calls to interact with these items, but then you can't use Sitecore Caching without custom backend caching code). Alternately, you can split your API into three different trees:
[siteroot]/API/GET/*/*/*/*/*/*/*/*/*
[siteroot]/API/PUT/*/*/*/*/*/*/*/*/*
[siteroot]/API/POST/*/*/*/*/*/*/*/*/*
This allows caching the GET requests (since GET requests should only retrieve data, not update it). Be sure to use the proper caching scheme, essentially this should cache based on every permutation of the data, user, etc., if you intend to use this in any of those contexts.
If you are going to create multiple sublayouts, I recommend creating a base class that handles general methods for GET, PUT, and POST, and then use those classes as the base for your sublayouts.
In your sublayouts, you simply get the Request object, get the path (and query if you're using queries), split it, and perform your switch case logic just as you would with standard routing. For PUT, use Response.ReadBinary(). For POST use the Request.Form object to get all of the form elements and iterate through them to process the information provided (it may be easiest to put all of your form data into a single JSON object, encapsulated as a string (so .NET sees it as a string and therefore one single property) and then you only have one element in the post to deserialize depending on the POST path the user specified.
Complicated? Yes. Works? Yes. Recommended? Well... if you're in a shared environment (multiple sites) and you don't want this processing happening for EVERY site in the pipeline processor, then this solution works. If you have access to using MVC with Sitecore or have no issues altering the pipeline processor, then that is likely more efficient.
One benefit to the content based method is that the context lifecycle is exactly the same as a standard Sitecore page (logins, etc.), so you've got all the same controls as any other item would provide at that point in the lifecycle. The negative to this is that you have to deal with the entire page lifecycle load before it gets to your code... the pipeline processor can skip a lot of Sitecore's process and just get the data you need directly, making it faster.
you need to have a Pipeline initializer for Routing:
It will be like :
public class Initializer
{
public void Process(PipelineArgs args)
{
RouteCollection route = RouteTable.Routes;
route.MapHttpRoute("DefaultApi", "api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional });
}
}
On config file you will have :
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<initialize>
<processor type="_YourNameSpace.Initializer,_YourAssembly" />
</initialize>
</pipelines>
</sitecore>
</configuration>
Happy coding