tag:blogger.com,1999:blog-57784190594638793762024-03-18T22:43:30.863-07:00Adobe CQ/Adobe AEMBlog for How to in Adobe CQ or WEM by <a href="https://www.linkedin.com/in/upadhyayyogesh/">Yogesh Upadhyay</a>
<br><br>
<b><u>Disclaimer</u>: </b>Information provided in this blog is for test purpose only and express my personal view. I will not be held responsible for damage caused on your system because of information. Please don't try any suggestion in production system without proper testing. <b>This is not a Adobe supported blog.</b>Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.comBlogger118125tag:blogger.com,1999:blog-5778419059463879376.post-28401677125800907022022-01-03T19:43:00.002-08:002022-01-12T13:11:19.044-08:00How to build your own CMS [Episode 1 - Justification]<p>Past few years, I have been working with my team to build our own CMS for marketing content or SEO content, an audacious goal given that we were already using AEM, an enterprise level CMS with great integration with Adobe marketing cloud. In these blog post I will walk through mental model and architecture of how we went about building it.</p><p>In building any new product which is not part of your core business and for which good solution already exist, first question you gotta ask yourself or answer to others WHY BUILD ? or WHY NOT JUST BUY ?</p><p>I have seen multiple frameworks to help you decide which path to take (build vs buy), in our case since we were already using AEM we already knew some pain point (see below) with framework that help us make decision. When your company is very engineering driven and have frameworks, platform and system in place that very few has.Our criteria of justifying to leadership came down to 4 things,</p><p><b>Is this problem unique to you</b>: In this case NO. CMS is not a unique problem, many company has CMS needs for different use case and there is plethora of solution that exist for those use cases. </p><p><b>Is this part of your core business</b>: YES and NO, Core CMS feature it self is not part of Core business, Company is not going to build and sell enterprise level CMS. However there are certain product which uses subset of CMS features (we will get to that later) </p><p><b>Does this need white glove support</b>: If you buy you definitely need white glove support, specially with AEM getting support is harder, hiring someone who knows AEM or really good at it is even harder. And even if you hire them it hard to have a career path for them in other part of company. We struggled with hiring and retaining AEM talent.</p><p><b>Integration: </b>This was BIG one, if most of your app are custom integrating with third party solution is harder, all the way from using Data (Internal data), Infrastructure (using physical or virtual hardware running in same network), CI/CD (all the way from code hosting to canary testing to prod deployment), Accessibility, Security, Designs (align with visual design of rest of company and keeping system up to date) etc. We continuously struggled with integrating AEM with company stack, processes and infrastructure. </p><p>After using AEM for years we stack rank these criteria against our future need and decided to build our own CMS.</p><p>Well so far so good, but how would you go about justifying this to leadership and most important executing it. I have seen many companies trying it and not succeeding so it was big risk. In section two I will try to cover steps we took to go from justification to POC [Episode 2 - Proof of Concept] </p><p><br /></p><p>AEM pain points:</p><p></p><ul style="text-align: left;"><li><b>Not a true Microservice</b>: Given that how author, publish and communication between two (through replication) works, I don't think it is true microservice. It is really hard to scale AEM horizontally (both author and publish)</li><li><b>Technology & Ramp up</b>: Now this could be debatable but I think AEM tech stack is not widely used teach stack, for example app request processing (sling), Sightly (Templating language), Event handling (OSGI or sling events), Data replication (Proprietary), persistence (Tar), Apart from backend being in Java none of the other technologies are widely used and hence hard to find generalist and hard to ramp someone on this product. </li><li><b>High reliant on dispatcher</b>: Effective caching is still not a solved problem and AEM rely a lot on effective caching at dispatcher to do app level scaling. We could not scale system if you are service dynamic data.</li><li><b>Automation</b>: AEM deployment pipeline is tightly coupled, there are only few options you have to extend it, it makes it hard to integrate it with existing systems. </li><li><b>Code management</b>: Fact that actual code (front end) and bundles lives where content also lives do not provide good isolations and hard to do code management (versioning etc) and plug in in to existing deployment pipeline.</li><li><b>Upgrade</b>: Not sure how many of you faced this but upgrading AEM systems are not easy and takes a lot of resources. Engineers end of spending more time on upgrade than developing features.</li></ul><p></p><p> </p><p><br /></p>Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com0tag:blogger.com,1999:blog-5778419059463879376.post-37383671610391228062020-06-05T19:15:00.000-07:002020-06-05T19:17:52.456-07:00How to start sling with RDBMS<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Use case</b>: Start Sling using RDBMS (Mysql, Oracle) as a persistent manager.<br />
<br />
<b>Prerequisite</b>: Make sure that you have mysql or oracle install. Here is instruction <a href="https://dev.mysql.com/doc/mysql-installation-excerpt/5.7/en/">https://dev.mysql.com/doc/mysql-installation-excerpt/5.7/en/</a><br />
<br />
Currently sling comes out of the box with Tar and Mongo persistent manager but setting up RDBMS instruction is hard to find.<br />
<br />
Note that sling underneath has Oak for data persistence and OAK does support different type of RDB persistence that you can get it from here. <a href="https://jackrabbit.apache.org/oak/docs/nodestore/document/rdb-document-store.html">https://jackrabbit.apache.org/oak/docs/nodestore/document/rdb-document-store.html</a><br />
<br />
Here are steps to set up RDB persistence for sling,<br />
<br />
<br />
<b>Step 1</b>: Checkout sling project from <a href="https://sling.apache.org/downloads.cgi">https://sling.apache.org/downloads.cgi</a><br />
example<br />
<blockquote class="tr_bq">
git clone https://github.com/apache/sling-org-apache-sling-starter.git</blockquote>
OR<br />
<blockquote class="tr_bq">
git clone https://github.com/apache/sling-org-apache-sling-app-cms.git</blockquote>
<span style="color: red;"><br /></span>
<b>Step 2</b>: find oak.txt either under src/main/provisioning or builder/src/main/provisioning<br />
<br />
<b>Step 3</b>: Add the following lines in <i>oak.txt</i><br />
<br />
<blockquote class="tr_bq">
[artifacts startLevel=15 runModes=oak_rdb]<br />
<span style="white-space: pre;"> </span>mysql/mysql-connector-java/8.0.20<br />
<span style="white-space: pre;"> </span>com.h2database/h2-mvstore/1.4.194<br />
<span style="white-space: pre;"> </span>org.apache.sling/org.apache.sling.datasource/1.0.4</blockquote>
<br />
<blockquote class="tr_bq">
org.apache.sling.datasource.DataSourceFactory-mysql.config <br />
url="jdbc:mysql://localhost:3306/slingcms" <br />
driverClassName="com.mysql.jdbc.Driver" <br />
username="root" <br />
password="" <br />
datasource.name="oak"<br />
validationQuery="show\ tables"<br />
connectionProperties="serverTimezone\=UTC"</blockquote>
<b>Step 4</b>: Find boot.txt which is under the same folder where oak.txt was and append the following in property <i>sling.run.mode.install.options</i><br />
<br />
sling.run.mode.install.options=oak_tar,oak_mongo,<b>oak_rdb</b><br />
<b><br /></b>
<b>Step 5: </b>Build project using<br />
<blockquote class="tr_bq">
mvn clean install</blockquote>
<br />
<b>Step 6</b>: Copy stand-alone jar files to the location where you want to run the project (Usually they are under target folder at root or builder directory)<br />
<br />
<div style="text-align: left;">
<b>Step 7</b>: Run following command </div>
<blockquote class="tr_bq" style="text-align: left;">
java -jar -Dsling.run.modes=oak_rdb <jar file> start</blockquote>
<b>Step 8</b>: To check if right tables are created you can down load any mysql explorer <a href="https://www.mysql.com/products/workbench/">https://www.mysql.com/products/workbench/</a> and check<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBUbilDe6qrW38Z3sh58yl8mo0LEM_b2syGDNtJY9QMQu5teN0JkcJMOEBoiH9CpG1WTVZCfyHKIr4KwekPMiufJlhH6wnaQQZWuMXb-TLCDCCFmyNerCXPiW6PUyPuBgYmlzXwBbtYDQ/s1600/Screen+Shot+2020-06-05+at+7.13.44+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="482" data-original-width="1362" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBUbilDe6qrW38Z3sh58yl8mo0LEM_b2syGDNtJY9QMQu5teN0JkcJMOEBoiH9CpG1WTVZCfyHKIr4KwekPMiufJlhH6wnaQQZWuMXb-TLCDCCFmyNerCXPiW6PUyPuBgYmlzXwBbtYDQ/s640/Screen+Shot+2020-06-05+at+7.13.44+PM.png" width="640" /></a></div>
<br />
<br />
<br />
<br /></div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com0tag:blogger.com,1999:blog-5778419059463879376.post-85815467570421105772018-01-08T09:29:00.000-08:002018-01-08T09:29:10.707-08:00How to work with Report in CQ / WEM<div dir="ltr" style="text-align: left;" trbidi="on">
Use Case: You want to create custom report for any thing in CQ<br />
<br />
Prerequisite: Please read very carefully<br />
<br />
<ul style="text-align: left;">
<li><a href="http://dev.day.com/docs/en/cq/current/administering/reporting.html" target="_blank">http://dev.day.com/docs/en/cq/current/administering/reporting.html</a></li>
<li><a href="http://dev.day.com/docs/en/cq/current/developing/developing-reports.html" target="_blank">http://dev.day.com/docs/en/cq/current/developing/developing-reports.html</a></li>
</ul>
<br />
What we are covering:<br />
<br />
I will give one custom example and guide you how to create report within CQ for your custom requirement.<br />
<br />
Q: Where I can find all CQ OOTB reports.<br />
A: You can find them under /etc/reports. You can also navigate to CQ report using siteadmin -> tools-> /reports -> double click on any report<br />
<br />
Q: Where is code for OOTB reporting templates and component<br />
A: They can be found under /libs/cq/reporting and API <a href="http://dev.day.com/docs/en/cq/current/javadoc/com/day/cq/reporting/package-summary.html" target="_blank">http://dev.day.com/docs/en/cq/current/javadoc/com/day/cq/reporting/package-summary.html</a> (I don't think you might have to use these API, Unless there is any specific requirement )<br />
<br />
If you read above document very carefully, You will find that not all the reports comes with CQ uses CQ reporting framework. Specially Request log parser report and Disk Usage report.<br />
<br />
We will cover CQ reporting example here using CQ reporting framework. For any other report please use example of disk usage or log parser report.<br />
<br />
Requirement:<br />
<br />
Create CQ report to get Geometrixx product page information. Report should include,<br />
<br />
1) Title<br />
2) Tags<br />
3) URL<br />
4) Overview Link<br />
5) Feature Link<br />
<br />
You should be able to group report based on Tags. You should also be able to see chart representation of report. You should also be able to export report outside CQ instance.<br />
<br />
<br />
Solution:<br />
<br />
First, Make sure that this can be done using CQ reporting framework. For that go through each field for report and make sure that those are available as properties within that page through "Fix" path and there is no complex logic involve to get that data.<br />
<br />
Once you know that this can be done using CQ reports, Start developing report.<br />
<br />
Step 1: Create template<br />
<br />
<br />
<ul style="text-align: left;">
<li>Create a template for your report. See example under /libs/cq/reporting/templates. </li>
<li>Create node called /apps/cq/reporting/templates</li>
<li>Easy is to copy existing report from /libs (I copied user report) to /apps and rename it. In our case I created a report called /apps/cq/reporting/templates/productReport</li>
<li>Go to /apps/cq/reporting/templates/productReport/jcr:content/report and assign resource type for your custom report. Also create a property called "rootPath" and assign value as "/content/geometrixx/en/products"</li>
<li>Template will look like this.</li>
</ul>
<div>
<div class="p1">
<span class="s1"><?</span><span class="s2">xml</span><span class="s3"> </span>version<span class="s3">=</span><span class="s4">"1.0"</span><span class="s3"> </span>encoding<span class="s3">=</span><span class="s4">"UTF-8"</span><span class="s1">?></span></div>
<div class="p2">
<span class="s1"><</span><span class="s2">jcr:root</span><span class="s3"> </span><span class="s5">xmlns:sling</span><span class="s3">=</span>"http://sling.apache.org/jcr/sling/1.0"<span class="s3"> </span><span class="s5">xmlns:cq</span><span class="s3">=</span>"http://www.day.com/jcr/cq/1.0"<span class="s3"> </span><span class="s5">xmlns:jcr</span><span class="s3">=</span>"http://www.jcp.org/jcr/1.0"<span class="s3"> </span><span class="s5">xmlns:nt</span><span class="s3">=</span>"http://www.jcp.org/jcr/nt/1.0"</div>
<div class="p2">
<span class="s3"> </span><span class="s5">jcr:description</span><span class="s3">=</span>"Geometrixx Product Report"</div>
<div class="p1">
<span class="s3"> </span>jcr:primaryType<span class="s3">=</span><span class="s4">"cq:Template"</span></div>
<div class="p2">
<span class="s3"> </span><span class="s5">jcr:title</span><span class="s3">=</span>"Geometrixx Product Report"</div>
<div class="p2">
<span class="s3"> </span><span class="s5">allowedPaths</span><span class="s3">=</span>"[/etc/reports(/.*)?]"</div>
<div class="p2">
<span class="s3"> </span><span class="s5">ranking</span><span class="s3">=</span>"{Long}100"</div>
<div class="p2">
<span class="s3"> </span><span class="s5">shortTitle</span><span class="s3">=</span>"Product Report"<span class="s1">></span></div>
<div class="p3">
<span class="s3"> </span><span class="s1"><</span>jcr:content</div>
<div class="p2">
<span class="s3"> </span><span class="s5">jcr:primaryType</span><span class="s3">=</span>"cq:PageContent"</div>
<div class="p2">
<span class="s3"> </span><span class="s5">sling:resourceType</span><span class="s3">=</span>"cq/reporting/components/reportpage"<span class="s1">></span></div>
<div class="p4">
<span class="s1"><</span><span class="s2">report</span></div>
<div class="p2">
<span class="s3"> </span><span class="s5">jcr:primaryType</span><span class="s3">=</span>"nt:unstructured"</div>
<div class="p2">
<span class="s3"> </span><b><span class="s5">sling:resourceType</span><span class="s3">=</span>"cq/reporting/components/productreport/productreport"</b></div>
<div class="p4">
<span class="s5">repVersion</span>=<span class="s4">"{Long}2"</span></div>
<div class="p2">
<span class="s3"> </span><b><span class="s5">rootPath</span><span class="s3">=</span>"/content/geometrixx/en/products"</b><span class="s1">/></span></div>
<div class="p3">
<span class="s3"> </span><span class="s1"></</span>jcr:content<span class="s1">></span></div>
<div class="p3">
<span class="s1"></</span>jcr:root<span class="s1">></span></div>
</div>
<br />
<br />
Step 2: Create Component<br />
<br />
<ul style="text-align: left;">
<li>You can see example under /libs/cq/reporting/components/<I copied userreport>. Copy directory structure under /<b>cq/reporting/components and rename it as </b><b>productreport</b></li>
<li>Create / Rename (/libs/cq/reporting/components/userreport/userreport to cq/reporting/components/productreport/productreport)</li>
<li>Make sure that you have following nodes, /apps/cq/reporting/components/productreport/productreport/charting for creating chart data for grouped items. /apps/cq/reporting/components/productreport/productreport/dialog for existing report dialogs. /libs/cq/reporting/components/userreport/userreport/queryBuilder to specify query that needs to run against the report.</li>
<li>Change /libs/cq/reporting/components/userreport/userreport/queryBuilder, nodeType property to "cq:PageContent". Because your page jcr:content node has all those properties that we are looking for in our report.</li>
<li>Please see http://dev.day.com/docs/en/cq/current/developing/developing-reports.html#Query Definition if you want to add additional constraint in query. For example give me only those page whose cq:template value is "Something", In that case you would create something like this</li>
</ul>
<div>
<pre style="background-color: #f0f6fc; color: #444444; font-size: 12px; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 1em 0px 1.5em;">N:queryBuilder
N:propertyConstraints
[
N:N0 // array of nodes (name irrelevant), each with the following properties:
P:cq:template
P:something
]
P:nodeTypes cq:PageContent</pre>
</div>
<div>
Step 3: Create all Column</div>
<div>
<br /></div>
<div>
<ul style="text-align: left;">
<li>Once we have query definition to get all pages, Now you can create column to show in your report.</li>
<li>For that see example under /libs/cq/reporting/components/userreport and see how each column is configured.</li>
<li>You can copy one column from /libs/cq/reporting/components/userreport under /apps/cq/reporting/components/productreport to start with</li>
<li>Description about field for a column can be found here http://dev.day.com/docs/en/cq/current/developing/developing-reports.html#Column Base Component</li>
<li>For example in our case, we want a Tag column. for that create /apps/cq/reporting/components/productreport/productreport/Tagcol with following definition</li>
<li>Now suppose you want overview page path, for that you have to nevigate to Overview node and then show it. In that case definition would look like this</li>
</ul>
</div>
<br /></div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com38tag:blogger.com,1999:blog-5778419059463879376.post-56161883942877320982017-04-05T10:31:00.000-07:002017-04-05T10:32:12.705-07:00How to create custom renderer for a file type in AEM<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Use Case</b>:<br />
<br />
Honestly use cases for this could be different based on what you want to change in response for a specific file type. We will take an example where we want to add some custom header for a PDF file based on what author has added in property of that file. For example here if author has added a canonical url and no index property, then we want to add these property in response header of all pdf file request.<br />
<br />
<b>Prerequisite</b>:<br />
<br />
Note that in order to make these property available for asset, you have
to override asset editor as well. One example of adding extra property
to asset editor is here
http://www.wemblog.com/2013/01/how-to-associate-cug-with-dam-asset-in.html<br />
<br />
<b>Implementation</b>:<br />
Key here is OptingServlet <a href="https://sling.apache.org/apidocs/sling7/org/apache/sling/api/servlets/OptingServlet.html" target="_blank">https://sling.apache.org/apidocs/sling7/org/apache/sling/api/servlets/OptingServlet.html</a> which get invoked on every request. Here is one example <br />
<br /></div>
<script src="https://gist.github.com/yupadhyay/2ed7ee10d38c6f10b13e759268948887.js"></script>
<b>Note:</b> Let me know if you have any question about implementation.</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com14tag:blogger.com,1999:blog-5778419059463879376.post-61180646283631466072016-12-09T13:39:00.001-08:002016-12-09T13:39:23.745-08:00How to Write Tests in AEM<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Use Case:</b> Writing tests for AEM application. <br />
<br />
<b>Current Issue:</b> As your project and code base grows, it is really important to make sure that test coverage for code is there to maintain consistency and sanity of your code. Writing test cases for AEM is little bit different than writing conventional Java test cases, This makes it difficult for beginner to write test cases for AEM application. <br />
<br />
Idea of this post to give different options available for writing unit test for AEM services.<br />
<br />
<b>Prerequisite</b>:<br />
<ul style="text-align: left;">
<li>Familiar with Java Junit test framework <a href="http://junit.org/" target="_blank">http://junit.org</a></li>
<li>Familiar with Java Mockito test framework <a href="http://site.mockito.org/">http://site.mockito.org/</a></li>
<li>Optional: PowerMockito test framework <a href="http://powermock.github.io/">http://powermock.github.io/</a></li>
</ul>
<b>Good to know</b>:<br />
<ul style="text-align: left;">
<li>Sling test framework (Mock and IT) <a href="https://sling.apache.org/documentation/development.html" target="_blank">https://sling.apache.org/documentation/development.html</a></li>
<li>AEM Mock <a href="http://wcm.io/testing/aem-mock/">http://wcm.io/testing/aem-mock/</a> and <a href="http://wcm.io/testing/aem-mock/apidocs/">http://wcm.io/testing/aem-mock/apidocs/</a></li>
<li>WCMUse classes Mocking <a href="http://aempodcast.com/2015/testing/unit-testing-wcmuse-classes-using-mockito/#.WEmiUMMrJKc" target="_blank">http://aempodcast.com/2015/testing/unit-testing-wcmuse-classes-using-mockito/#.WEmiUMMrJKc</a> </li>
</ul>
I would explain how you can have better test coverage for your application by giving different use cases,<br />
<br />
<b>Dependencies: </b>It is recommended to have following dependencies in to your pom before start writing for tests for your application<br />
<script src="https://gist.github.com/yupadhyay/6694381bce940365399f5808af1f9006.js"></script>
<b>Case 1: </b>Writing test cases for Generic Helper class.<br />
<br />
This is simplest use case where your generic helper class (For example StringUtils, DateUtils) is not using any AEM libraries. For this you can simply use Junit to write your unit test. <a href="https://www.tutorialspoint.com/junit" target="_blank">https://www.tutorialspoint.com/junit</a><br />
<br />
Here is very simple example:<br />
<br />
<script src="https://gist.github.com/yupadhyay/177034d7b91250458ff9e05a8b72982d.js"></script>
<br />
<b>Case 2: Writing test cases for AEM Helper class</b><br />
<br />
This is second use case where you want to test AEM helper methods. For this you can use combination of Junit and Mockito. Use Mockito to Mock AEM services and methods and Junit for assertion.<br />
<br />
Here is simple example<br />
<br />
<script src="https://gist.github.com/yupadhyay/32f17fc2d32e830ac689908005753c0e.js"></script>
<b>Case 3: Writing test cases for AEM services</b><br />
<br />
Now it gets little bit tricky where you need to mock certain behavior of bundle and implicit object. That's why Sling has created Mock version of sling objects and wcm.io has created mock version of AEM objects. You can just use aem mock <a href="http://wcm.io/testing/aem-mock/" target="_blank">http://wcm.io/testing/aem-mock/</a> to achieve most of your use cases. (AEM mock extend Sling mock).<br />
<br />
here are some of the common use cases you will come across while testing your service.<br />
<br />
1) How can I mock content my service is running against ?<br />
<br />
For this it is recommended to use contentLoader API <a href="http://wcm.io/testing/aem-mock/usage.html" target="_blank">http://wcm.io/testing/aem-mock/usage.html</a> to either load existing json based resource (You can simply get it by creating resource in CRXDE and then using something like RESOURCEPATH.infinity.json to get json for that resource) or just create mock resource using ContentBuilder context.create().resource() or ResourceBuilder context.build().resource() <a href="http://wcm.io/testing/aem-mock/apidocs/" target="_blank">http://wcm.io/testing/aem-mock/apidocs/</a><br />
<br />
Note that if you are mocking Page object then you have to use aem mock using aemcontext.pageManager().create() <br />
<br />
2) How Can I initialize properties in the bundle ?<br />
<br />
You can use register and activate OSGI service with properties http://wcm.io/testing/aem-mock/usage.html#Registering_OSGi_service for that. Here is some example<br />
<br />
<script src="https://gist.github.com/yupadhyay/b73e8239f7dee0f2956cd93d338c9bc1.js"></script>
<br />
3) How Can I inject other service for my service ?<br />
<br />
You can either Mock service or use register service API for that <a href="http://wcm.io/testing/aem-mock/usage.html#Registering_OSGi_service" target="_blank">http://wcm.io/testing/aem-mock/usage.html#Registering_OSGi_service</a><br />
<br />
Note that when you inject a service to your service using Reference then you have to register this your injected service, otherwise your test will fail.<br />
<br />
4) How Can I test sling model ?<br />
<br />
You can use aemContext for that. <a href="http://wcm.io/testing/aem-mock/usage.html#Sling_Models" target="_blank">http://wcm.io/testing/aem-mock/usage.html#Sling_Models</a><br />
<br />
<br />
<b>Case 4: Writing test cases for AEM servlets and filters</b><br />
<br />
This is very similar to how you would do test cases for Service. For request and response you either have to mock request / response object using Mockito or Use Spy or use sling request and response mock. Since a lot of methods in filter and servlet do not return any result, Make Mockito verify your friend. Here is one example using simple mockito to test servlet<br />
<br />
<br />
<script src="https://gist.github.com/yupadhyay/72aacb699429ce728ec5801b19f319f8.js"></script>
<br />
<b> How can I measure my test coverage ?</b><br />
<br />
You can use jococo test coverage plugin along with your build system to measure this coverage. You can have following plugin in to your parent pom<br />
<br />
<script src="https://gist.github.com/yupadhyay/808a45c73b3dfdea85e6757246ff29eb.js"></script>
<br />
<br />
<b>How Can I write Integration test in AEM ?</b><br />
<br />
Very good example here <a href="https://github.com/sneakybeaky/AEM-Integration-Test-Example" target="_blank">https://github.com/sneakybeaky/AEM-Integration-Test-Example</a><br />
<br />
It is based of sling test base <a href="https://sling.apache.org/documentation/development/sling-testing-tools.html" target="_blank">https://sling.apache.org/documentation/development/sling-testing-tools.html</a><br />
<br />
I know this information is not enough to have you set up for writing tests in AEM. Feel free to let me know if you have more question and I will add more stuff here.
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com27tag:blogger.com,1999:blog-5778419059463879376.post-89264275776319391942016-02-07T12:37:00.000-08:002016-03-09T10:14:52.245-08:00How to Sightly in AEM / CQ<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Use Case:</b> Some common how to in Sightly<br />
<br />
<b>Prerequisite:</b> Please read following document carefully before some other How to questions<br />
<br />
<ul style="text-align: left;">
<li>Sightly Specification: <a href="https://github.com/Adobe-Marketing-Cloud/sightly-spec/blob/master/SPECIFICATION.md" target="_blank">https://github.com/Adobe-Marketing-Cloud/sightly-spec/blob/master/SPECIFICATION.md</a> </li>
<li>Basics of Sightly: <a href="https://docs.adobe.com/docs/en/aem/6-1/develop/sightly.html" target="_blank">https://docs.adobe.com/docs/en/aem/6-1/develop/sightly.html</a></li>
<li>Sightly tutorials: <a href="http://blogs.adobe.com/experiencedelivers/experience-management/sightly-intro-part-1/" target="_blank">http://blogs.adobe.com/experiencedelivers/experience-management/sightly-intro-part-1/</a> (Check other parts on same page)</li>
<li>Sightly Presentation: <a href="http://www.slideshare.net/GabrielWalt/component-development">http://www.slideshare.net/GabrielWalt/component-development</a></li>
<li>Code Base: <a href="https://github.com/apache/sling/tree/trunk/bundles/scripting/sightly" target="_blank">https://github.com/apache/sling/tree/trunk/bundles/scripting/sightly</a> </li>
</ul>
<h3 style="text-align: left;">
Here is some common How to in sightly</h3>
<br />
<ul style="text-align: left;">
<li><h4>
How to include ClientLibs in Sightly </h4>
</li>
</ul>
<script src="https://gist.github.com/yupadhyay/a7348e7fbf98590f176c.js"></script>
<br />
<ul style="text-align: left;">
<li><h4>
How to Loop fixed number of set in Sightly </h4>
</li>
</ul>
<script src="https://gist.github.com/yupadhyay/3198704b7ba7b4ccc9bf.js"></script>
<br />
<ul style="text-align: left;">
<li><h4>
How to create for or while loop in sightly</h4>
</li>
</ul>
<div style="text-align: left;">
You can not have dynamic while loop directly in Sightly scripting. However you can use Use class to simulate while or for loop in Sightly. Here is example </div>
<script src="https://gist.github.com/yupadhyay/1f069aeb665dfd04a85e.js"></script>
<br />
<ul style="text-align: left;">
<li><h4>
How to reference other OSGI service in sightly </h4>
</li>
</ul>
You can not directly reference OSGI service in sightly template. However you can reference them in use class using <span style="color: blue;">getSlingScriptHelper().getService(Service.class)</span> note that you can not use @Reference to refer a service in sightly class.<br />
<br />
<ul style="text-align: left;">
<li><h4>
How to initialize a default value of a property in sightly</h4>
</li>
</ul>
Best way to initialize a value is in activate method of use class. You can also do it in sightly template using something like <sly data-sly-test.parentNavName="${currentPage.properties.navTitle || currentPage.title || currentPage.pageTitle }"> and then use ${parentNavName}<br />
<ul style="text-align: left;">
<li><h4>
How to access string array in Sightly </h4>
</li>
</ul>
This is pretty much similar to what we did in for loop. Here is some more generic example<br />
<script src="https://gist.github.com/yupadhyay/aa9739d4235c66aa9b18.js"></script>
<br />
<ul style="text-align: left;">
<li><h4>
How to create/access map in sightly </h4>
</li>
</ul>
Here is one example of how you can do that<br />
<script src="https://gist.github.com/yupadhyay/84ae7b17e50ebf420605.js"></script>
<br />
<ul style="text-align: left;">
<li><h4>
How to use Sling Model with Sightly</h4>
</li>
</ul>
Here is one example of how you can do it. Note that You can also create sling model for a resource and then use other use classes to return sling model.<br />
<br />
<script src="https://gist.github.com/yupadhyay/92d4fab81439a322e58e.js"></script>
<br />
<div>
<ul style="text-align: left;">
<li><h4>
How to hide element in Sightly</h4>
</li>
</ul>
You can use either data-sly-unwrap or <sly> tag for this here is example</div>
<div>
</div>
<div>
<pre style="-webkit-text-stroke-width: 0px; background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; orphans: auto; overflow: auto; padding: 16px; text-align: start; text-indent: 0px; text-transform: none; widows: 1; word-break: normal; word-spacing: 0px; word-wrap: normal;"><span class="pl-c" style="box-sizing: border-box; color: #969896;"><!--/* This will only show "Foo" (without a <div> around) if the test is true: */--></span>
<<span class="pl-ent" style="box-sizing: border-box; color: #63a35c;">div</span> <span class="pl-e" style="box-sizing: border-box; color: #795da3;">data-sly-test</span>=<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box; color: #183691;">"</span>${myTest}<span class="pl-pds" style="box-sizing: border-box; color: #183691;">"</span></span> <span class="pl-e" style="box-sizing: border-box; color: #795da3;">data-sly-unwrap</span>>Foo</<span class="pl-ent" style="box-sizing: border-box; color: #63a35c;">div</span>>
<span class="pl-c" style="box-sizing: border-box; color: #969896;"><!--/* This would show a <div> around "Foo" only if the test is false: */--></span>
<<span class="pl-ent" style="box-sizing: border-box; color: #63a35c;">div</span> <span class="pl-e" style="box-sizing: border-box; color: #795da3;">data-sly-unwrap</span>=<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box; color: #183691;">"</span>${myTest}<span class="pl-pds" style="box-sizing: border-box; color: #183691;">"</span></span>>Foo</<span class="pl-ent" style="box-sizing: border-box; color: #63a35c;">div</span>></pre>
</div>
<div>
<pre style="-webkit-text-stroke-width: 0px; background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; orphans: auto; overflow: auto; padding: 16px; text-align: start; text-indent: 0px; text-transform: none; widows: 1; word-break: normal; word-spacing: 0px; word-wrap: normal;"><span class="pl-c" style="box-sizing: border-box; color: #969896;"><!--/* This will display only the output of the 'header' resource, without the wrapping <sly> tag */--></span>
<<span class="pl-ent" style="box-sizing: border-box; color: #63a35c;">sly</span> <span class="pl-e" style="box-sizing: border-box; color: #795da3;">data-sly-resource</span>=<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box; color: #183691;">"</span>./header<span class="pl-pds" style="box-sizing: border-box; color: #183691;">"</span></span>></<span class="pl-ent" style="box-sizing: border-box; color: #63a35c;">sly</span>></pre>
</div>
<div>
<pre style="-webkit-text-stroke-width: 0px; background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; orphans: auto; overflow: auto; padding: 16px; text-align: start; text-indent: 0px; text-transform: none; widows: 1; word-break: normal; word-spacing: 0px; word-wrap: normal;"><<span class="pl-ent" style="box-sizing: border-box; color: #63a35c;">sly</span> <span class="pl-e" style="box-sizing: border-box; color: #795da3;">data-sly-unwrap</span>=<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box; color: #183691;">"</span>${false}<span class="pl-pds" style="box-sizing: border-box; color: #183691;">"</span></span>></<span class="pl-ent" style="box-sizing: border-box; color: #63a35c;">sly</span>> <span class="pl-c" style="box-sizing: border-box; color: #969896;"><!--/* outputs: <sly></sly> */--></span></pre>
</div>
<div>
<br />
<ul style="text-align: left;">
<li><h4>
How to pass a sightly object as parameter in Sightly</h4>
</li>
</ul>
</div>
<div>
<script src="https://gist.github.com/yupadhyay/da0bc42a931278c81577.js"></script>
More use cases to come. Please suggest me any use case you want to get clarity on.<br />
<br />
<h3 style="text-align: left;">
Some more useful Link:</h3>
<ul style="text-align: left;">
<li>Creating First Sightly Component: <a href="https://helpx.adobe.com/experience-manager/using/creating-sightly-component.html" target="_blank">https://helpx.adobe.com/experience-manager/using/creating-sightly-component.html</a></li>
<li>Create a AEM project with Sightly Example: <a href="https://github.com/Adobe-Marketing-Cloud/aem-project-archetype">https://github.com/Adobe-Marketing-Cloud/aem-project-archetype</a> </li>
<li>Good Example of Sightly Application using Sling: <a href="https://github.com/nateyolles/publick-sling-blog" target="_blank">https://github.com/nateyolles/publick-sling-blog</a> </li>
<li>Sightly To do App: <a href="https://github.com/Adobe-Marketing-Cloud/aem-sightly-sample-todomvc" target="_blank">https://github.com/Adobe-Marketing-Cloud/aem-sightly-sample-todomvc</a> </li>
<li>All Available Context and implicit object in JS and JAVA: <a href="http://aemtuts.com/aem-sightly-quick-reference/" target="_blank">http://aemtuts.com/aem-sightly-quick-reference/</a></li>
<li>All Available global Object: <a href="https://docs.adobe.com/docs/en/aem/6-0/develop/sightly/global-objects.html" target="_blank">https://docs.adobe.com/docs/en/aem/6-0/develop/sightly/global-objects.html</a> </li>
</ul>
Tooling For Sightly:<br />
<ul style="text-align: left;">
<li>Repl Tool: <a href="https://github.com/Adobe-Marketing-Cloud/aem-sightly-repl" target="_blank">https://github.com/Adobe-Marketing-Cloud/aem-sightly-repl</a> </li>
<li>Bracket Extension: <a href="https://docs.adobe.com/docs/en/dev-tools/aem-brackets.html" target="_blank">https://docs.adobe.com/docs/en/dev-tools/aem-brackets.html</a> </li>
<li>Eclipse Extension: <a href="https://docs.adobe.com/docs/en/dev-tools/aem-eclipse.html" target="_blank">https://docs.adobe.com/docs/en/dev-tools/aem-eclipse.html</a> </li>
</ul>
<ul style="text-align: left;">
</ul>
<ul style="text-align: left;">
</ul>
</div>
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com7tag:blogger.com,1999:blog-5778419059463879376.post-16693196470479300102016-01-29T11:27:00.001-08:002016-01-29T11:28:19.686-08:00How to perform Tree Activation in CQ AEM<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Use Case:</b> You want to tree activate a page as part of your code or schedule<b>r</b><br />
<b><br /></b>
<b>Example:</b><br />
<br />
<b>Replication Helper Class</b><br />
<br />
<script src="https://gist.github.com/yupadhyay/0f1cba64fbb32cd7f9c7.js"></script>
<b> </b><br />
<br />
<b>Tree Activation Service</b><br />
<br />
<script src="https://gist.github.com/yupadhyay/1fada42d3b2bef239e5d.js"></script>
<b>Tree Activation Impl</b><br />
<br />
<b><br /></b>
<script src="https://gist.github.com/yupadhyay/48a62cf34eaf762a72fa.js"></script>
<br />
<b>Note</b>: In above example replication action is performed using admin user. You could also create a replication user and use that user to replicate instead.
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com0tag:blogger.com,1999:blog-5778419059463879376.post-14437692079279719712015-10-07T09:12:00.001-07:002015-10-07T10:23:31.164-07:00How to extend Replication Page Process for workflow in AEM<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Use Case:</b> You want to extend existing replication page process and add your own logic during workflow step. Some of common use case could be,<br />
1) Activate Asset as soon as it is uploaded to DAM<br />
<br />
<b>Solution:</b><br />
<br />
Here is sample code you can use for this,<br />
<br />
What this code is doing is trying to find DAM asset path from workflow item and then activating DAM asset instead of activating just original node when OOTB activate page workflow is used. <br />
<br />
<script src="https://gist.github.com/yupadhyay/4e9b4d21a1a4561a5c6e.js"></script>
<br />
<br />
Once you add your code, you can add this as workflow step in your workflow. If you are extending model.xml for workflow then it will look something like this,<br />
<br />
<node<br />
jcr:primaryType="cq:WorkflowNode"<br />
description="A process to activate a page or asset"<br />
title="Activate Original Asset"<br />
type="PROCESS"><br />
<metaData<br />
jcr:primaryType="nt:unstructured"<br />
PROCESS="com.wemblog.ActivateAssetFromOriginalProcess"<br />
PROCESS_AUTO_ADVANCE="true"/><br />
</node><br />
<br />
Also you have to make sure that you have right dependency in your pom.xml. If you are using AEM6.1 then you need to use<br />
<br />
<dependency><br />
<groupId>com.adobe.aem</groupId><br />
<artifactId>uber-jar</artifactId><br />
<version>6.1.0</version><br />
<classifier>apis</classifier><br />
<scope>provided</scope><br />
</dependency><br />
<br />
As usual if you have any question or comment please let me know.</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com2tag:blogger.com,1999:blog-5778419059463879376.post-90932162937722573742015-03-13T11:27:00.000-07:002015-03-16T14:55:57.142-07:00How to set up Shareable Docker Image for Adobe CQ/AEM<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<h2 id="UsingDockerWithMicrosites-Usecase" style="text-align: left;">
Use case</h2>
<ul>
<li>Large Set up time for developers</li>
<li>Inconsistent environments across all boxes</li>
<li>Flexible in container testing</li>
<li>No Single repository for whole system artifacts </li>
</ul>
<div>
<h2 id="UsingDockerWithMicrosites-WhatisDocker">
What is Docker</h2>
<a class="external-link" href="https://www.docker.com/" rel="nofollow"><strong>Docker</strong></a><span style="color: #394d54;"> is
a platform for developers and sysadmins to develop, ship, and run
applications. Docker lets you quickly assemble applications from
components and eliminates the friction that can come when shipping code.
Docker lets you get your code tested and deployed into production as
fast as possible.</span><br />
<span style="color: #394d54;">More information about Docker can be found here <a class="external-link" href="https://docs.docker.com/" rel="nofollow">https://docs.docker.com/</a></span><br />
<span style="color: #394d54;">Check Docker Cheat sheet: <a class="external-link" href="https://github.com/wsargent/docker-cheat-sheet" rel="nofollow">https://github.com/wsargent/docker-cheat-sheet</a></span><br />
<br />
<h2 style="text-align: left;">
<span style="color: #394d54;">Set up</span></h2>
<strong><span style="color: #394d54;">Docker requires two part to work,</span></strong><br />
<ul>
<li><span style="color: #394d54;">Docker
Hub or Docker registry (Where images are stored). You don't have to set
up this part. We already have a private docker registry set up for you.</span></li>
<li><span style="color: #394d54;">Docker client (To work with docker images). You need to install this in your local. Please check <a class="external-link" href="https://docs.docker.com/installation/" rel="nofollow">https://docs.docker.com/installation/</a> and based on your OS you need to install one. I have instruction to install it on Redhat Linux.</span></li>
</ul>
<div>
<span style="color: #394d54;"><br /></span></div>
</div>
<div>
<h2>
What would you get after following below instruction ?</h2>
<br />
<ol>
<li>A Private Docker Hub, where you can manage AEM docker package. </li>
<li>A docker Image that will have author, publish and dispatcher instance.</li>
<li>Steps to manage your docker hub and local image and make changes to them.</li>
</ol>
<span style="color: #394d54;"><b><br /></b></span>
<b><u><span style="color: red;">Assumption:</span></u></b><span style="color: #394d54;"> I have docker registry set up for Red hat Linux. You might need different steps for different OS. I assume that on your OS mount you have a mount for /export. If this mount is not there then change paths in script.</span><br />
<span style="color: #394d54;"><br /></span>
<span style="color: #394d54;">Docker is only supported <b>FOR RED HAT LINUX VERSION > 6.5 </b></span><br />
<span style="color: #394d54;">(Use command cat /etc/*release to find your linux version)</span><br />
<span style="color: #394d54;"><br /></span>
<br />
<h2 style="text-align: left;">
<span style="color: #394d54;">Set Up Private Docker Registry</span></h2>
<span style="color: #394d54;"><br /></span>
<span style="color: #394d54;"><b>Prerequisite:</b> </span><br />
<span style="color: #394d54;"><br /></span>
<span style="color: #394d54;">If you are using redhat then </span></div>
<div>
<span style="color: #394d54;"><br /></span></div>
<div>
<span style="color: #394d54;"><b>Reference:</b></span></div>
<div>
<span style="color: #394d54;"><br /></span></div>
<div>
<span style="color: #394d54;">https://github.com/docker/docker-registry</span></div>
<div>
<span style="color: #394d54;"><br /></span></div>
<div>
<span style="color: #394d54;">https://www.digitalocean.com/community/tutorials/how-to-set-up-a-private-docker-registry-on-ubuntu-14-04</span></div>
<div>
<span style="color: #394d54;"><br /></span></div>
<script src="https://gist.github.com/yupadhyay/f90e52b6ce10799f3752.js"></script>
</div>
<br />
<br />
<h3 style="text-align: left;">
Set Up docker Image using docker file</h3>
<br />
Once docker is install create a dummy directory and put your jar file, license file, Hotfix and other files in to it. More information about Docker file <a href="https://docs.docker.com/reference/builder/" target="_blank">https://docs.docker.com/reference/builder/</a><br />
<br />
<b>Assumption:</b><br />
<br />
1) You have AEM jar file<br />
2) You have License File<br />
3) You have your version of JDK<br />
4) You have compiled HTTPD<br />
5) They all are in same folder where Dockerfile is<br />
<br />
For this create a file called Dockerfile and copy below. MAKE CHANGES BASED ON YOUR REQUIREMENT<br />
<br />
<br />
<br />
<script src="https://gist.github.com/yupadhyay/8019f9fcb4305d96ee81.js"></script>
</div>
Once Docker file is there build and create your private docker image using following command. This will create a shareable docker image
<br />
<br />
<script src="https://gist.github.com/yupadhyay/1482e45c27074ae43cda.js"></script>
<br />
Once Docker registry is installed and you have shareable image, now you can install docker client on any other machine<br />
<br />
<h2 style="text-align: left;">
Set up Docker Client</h2>
<div>
<b>Prerequisite:</b> Based on your OS please install docker client using <a href="https://docs.docker.com/installation/">https://docs.docker.com/installation/</a></div>
<div>
<br /></div>
<div>
<span style="color: #394d54;"><b>Change default path if there is not enough space</b></span><br />
<span style="color: #394d54;"><b><br /></b></span>
<span style="color: #394d54;">Docker by default get installed under /var/lib/docker in Red Hat. Make sure that you have enough space there. If not then you have to do following.</span><br />
<span style="color: #394d54;"><br /></span>
<script src="https://gist.github.com/yupadhyay/ab2bc87adb326aff34ef.js"></script>
<span style="color: #394d54;"><b>Set Up docker for Non SSL version</b></span><br />
<span style="color: #394d54;"><b><br /></b></span>
<span style="color: #394d54;">By default Docker uses SSL to communicate to docker registry. If you do not have valid cert installed then you might need to do following</span><br />
<span style="color: #394d54;"><br /></span>
<script src="https://gist.github.com/yupadhyay/dd18daa4652ee908d330.js"></script>
<span style="color: #394d54;"><br />Set up local docker instance using docker client</span><br />
<span style="color: #394d54;"><br /></span>
<span style="color: #394d54;">Do following to start your local AEM instance using docker registry and docker client</span><br />
<span style="color: #394d54;"><br /></span>
<span style="color: #394d54;"><br /></span><br />
<script src="https://gist.github.com/yupadhyay/fac0cb0778bd5ded7833.js"></script>
<strong style="line-height: 1.4285715;"><br /></strong>
<br />
<h2 id="UsingDockerWithMicrosites-Howtoupdatedockerimage">
How to update docker image</h2>
Please follow below step to update
your docker image<br />
<script src="https://gist.github.com/yupadhyay/660cdb43e0fb6abcdc9d.js"></script>
<br />
<div class="code panel pdl" style="border-width: 1px;">
<div class="codeContent panelContent pdl">
<div>
<div class="syntaxhighlighter nogutter bash" id="highlighter_321884">
<br />
<table border="0" cellpadding="0" cellspacing="0"><tbody>
<tr><td class="code"><div class="container" title="Hint: double-click to select code">
<div class="line number16 index15 alt1">
</div>
</div>
</td></tr>
</tbody></table>
</div>
</div>
</div>
</div>
<br />
<strong style="line-height: 1.4285715;"><br /></strong>
<strong style="line-height: 1.4285715;">Troubleshoot</strong><br />
<strong>Symptom</strong>: You are not able to access your instance from external machine<br />
<strong>Solution</strong>: Try to restart your machine using 'reboot' for linux box and restart in mac<br />
<strong>Symptom</strong>: Docker is not starting on mac<br />
<strong>Solution</strong>: Make sure that you have localhost entry in /etc/hosts file. e.g. 127.0.0.1 localhost. then do following<br />
<br />
<div class="code panel pdl" style="border-width: 1px;">
<div class="codeContent panelContent pdl">
<div>
<div class="syntaxhighlighter nogutter bash" id="highlighter_921861">
<table border="0" cellpadding="0" cellspacing="0"><tbody>
<tr><td class="code"><div class="container" title="Hint: double-click to select code">
<div class="line number1 index0 alt2">
<code class="bash plain">boot2docker delete</code></div>
<div class="line number2 index1 alt1">
<code class="bash plain">boot2docker download</code></div>
<div class="line number3 index2 alt2">
<code class="bash plain">boot2docker init</code></div>
<div class="line number4 index3 alt1">
<code class="bash plain">boot2docker up</code></div>
<div class="line number5 index4 alt2">
<code class="bash comments"># End of this you will be asked to add some env variable in your ~/.bash_profile</code></div>
<div class="line number6 index5 alt1">
<code class="bash comments"># Open bash profile and add them</code></div>
</div>
</td></tr>
</tbody></table>
</div>
</div>
</div>
</div>
<br />
<strong>Symptom</strong>: Getting following error in mac<br />
<div class="code panel pdl" style="border-width: 1px;">
<div class="codeContent panelContent pdl">
<div>
<div class="syntaxhighlighter nogutter bash" id="highlighter_409378">
<table border="0" cellpadding="0" cellspacing="0"><tbody>
<tr><td class="code"><div class="container" title="Hint: double-click to select code">
<div class="line number1 index0 alt2">
<code class="bash plain">FATA[0032] An error occurred trying to connect: Get https:</code><code class="bash plain">//192</code><code class="bash plain">.168.59.103:2376</code><code class="bash plain">/v1</code><code class="bash plain">.17</code><code class="bash plain">/containers/json</code><code class="bash plain">: dial tcp 192.168.59.103:2376: i</code><code class="bash plain">/o</code> <code class="bash plain">timeout</code></div>
</div>
</td></tr>
</tbody></table>
</div>
</div>
</div>
</div>
<strong>Solution</strong>: <a class="external-link" href="http://cxwangyi.github.io/notes/2015-01-13-docker-pitfalls.html" rel="nofollow">http://cxwangyi.github.io/notes/2015-01-13-docker-pitfalls.html</a><br />
<br />
<div class="code panel pdl" style="border-width: 1px;">
<div class="codeContent panelContent pdl">
<div>
<div class="syntaxhighlighter nogutter bash" id="highlighter_495626">
<table border="0" cellpadding="0" cellspacing="0"><tbody>
<tr><td class="code"><div class="container" title="Hint: double-click to select code">
<div class="line number1 index0 alt2">
<code class="bash plain">boot2docker stop</code></div>
<div class="line number2 index1 alt1">
<code class="bash plain">boot2docker destroy</code></div>
<div class="line number3 index2 alt2">
<code class="bash plain">boot2docker init</code></div>
<div class="line number4 index3 alt1">
<code class="bash plain">boot2docker up</code></div>
<div class="line number5 index4 alt2">
<code class="bash plain">docker version</code></div>
</div>
</td></tr>
</tbody></table>
</div>
</div>
</div>
</div>
<br />
<strong>Symptom</strong>: On Mac local box not able to access instance using localhost:<port number> (<a class="external-link" href="https://docs.docker.com/installation/mac/" rel="nofollow">https://docs.docker.com/installation/mac/</a>)<br />
<strong>Solution</strong>:<br />
<br />
<br />
<br />
<div class="code panel pdl" style="border-width: 1px;">
<div class="codeContent panelContent pdl">
<div>
<div class="syntaxhighlighter nogutter bash" id="highlighter_635532">
<table border="0" cellpadding="0" cellspacing="0"><tbody>
<tr><td class="code"><div class="container" title="Hint: double-click to select code">
<div class="line number1 index0 alt2">
<code class="bash comments"># Run following command</code></div>
<div class="line number2 index1 alt1">
<code class="bash functions">echo</code> <code class="bash string">"$(boot2docker ip) localhost"</code> <code class="bash plain">| </code><code class="bash functions">sudo</code> <code class="bash functions">tee</code> <code class="bash plain">-a </code><code class="bash plain">/etc/hosts</code></div>
<div class="line number3 index2 alt2">
<code class="bash comments"># Then access your instance using localhost </code></div>
<div class="line number4 index3 alt1">
<code class="bash comments"># If you want to create other vhost then change above command with your vhost. For example</code></div>
<div class="line number5 index4 alt2">
<code class="bash functions">echo</code> <code class="bash string">"$(boot2docker ip) localhost.wemblog.com"</code> <code class="bash plain">| </code><code class="bash functions">sudo</code> <code class="bash functions">tee</code> <code class="bash plain">-a </code><code class="bash plain">/etc/hosts</code></div>
<div class="line number5 index4 alt2">
<code class="bash plain"><br /></code></div>
<div class="line number5 index4 alt2">
</div>
</div>
</td></tr>
</tbody></table>
</div>
</div>
</div>
</div>
</div>
<div>
<span style="color: #394d54;"><br /></span>
<br />
<h2 style="text-align: left;">
<span style="color: #394d54;">Some use full docker command</span></h2>
<div>
<span style="color: #394d54;"><br /></span></div>
<script src="https://gist.github.com/yupadhyay/9b0c8c97bb32fcfac7d4.js"></script>
<br />
<div>
<h2 style="text-align: left;">
<span style="color: #394d54;">Upload content</span></h2>
<span style="color: #394d54;"><br /></span>
<span style="color: #394d54;">You can use Recap tool <a href="http://adamcin.net/net.adamcin.recap/">http://adamcin.net/net.adamcin.recap/</a> to install content once image is set up. You can even put this recap tool as part of your image when you are creating docker image. Just put them under install folder. </span><br />
<span style="color: #394d54;"><br /></span>
<span style="color: #394d54;">Note that every time you update your image, Uploaded content or local changes might get overriden. You have to commit your changes using docker commit and then apply update on top of that and then share your image.</span><br />
<span style="color: #394d54;"><br /></span>
<span style="color: #394d54;"><b>Useful resource:</b> <a href="http://www.techinsight.io/review/adobe-experience-manager/incontainer-testing-for-aem-with-docker/" target="_blank">http://www.techinsight.io/review/adobe-experience-manager/incontainer-testing-for-aem-with-docker/</a></span><br />
<span style="color: #394d54;"><br /></span>
<span style="color: #394d54;"><b>Note:</b> As usual let me know if you have any question.</span></div>
</div>
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com6tag:blogger.com,1999:blog-5778419059463879376.post-62928288404499514462014-12-10T11:14:00.004-08:002016-02-21T08:47:09.924-08:00How to Set Up Clustering In CQ/AEM 6 using MongoDB<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<h2 style="text-align: left;">
<b><u>Background:</u></b></h2>
<br />
With CQ / AEM 6 TarPM is not supported any more. AEM 6 ships with Oak which for now support TarMK and MongoMK Microkernal OOTB. More information about what is New Can be found from <a href="http://www.slideshare.net/AEMHub2014/oak-michael-marth" target="_blank">http://www.slideshare.net/AEMHub2014/oak-michael-marth</a> . With this change Support from Clustering is moved to actual storage layer it self (Which make more sense, given supporting all issues for clustering in earlier version). TarMK does not have replication or sharding feature so it comes down to MongoDB which support replication and sharding and hence enable High Availability (HA through replication) and Scalability (Through Sharding, Though this is still a question ?? See note below) through clustering in CQ /AEM 6.<br />
<br />
Here we will give step by step instruction of how to set up clustering using MongoDB in CQ<br />
<br />
<h2 style="text-align: left;">
<b><u>Pre requisite:</u></b></h2>
<br />
<ul style="text-align: left;">
<li>Make sure that You have CQ / AEM 6 jar file</li>
<li>Install MongoDB using instruction <a href="http://docs.mongodb.org/manual/installation/">http://docs.mongodb.org/manual/installation/</a></li>
<li>Make sure that it is up and running</li>
<li>Read about replication <a href="http://docs.mongodb.org/manual/core/replication-introduction/" target="_blank">http://docs.mongodb.org/manual/core/replication-introduction/</a></li>
<li>Read about deployment Strategy <a href="http://docs.adobe.com/docs/en/aem/6-0/deploy/recommended-deploys.html" target="_blank">http://docs.adobe.com/docs/en/aem/6-0/deploy/recommended-deploys.html</a></li>
</ul>
<div>
<i>There are two cases for setting Up Replica Set:</i></div>
<div>
<br /></div>
<div>
<b><u>Set up a new MongoDB Instance:</u></b></div>
<div>
<br /></div>
<div>
<ul style="text-align: left;">
<li>Set up additional MongoDB instance based on instruction above</li>
<li>Start any one of instance using ./mongod --port <Your Port> --dbpath <Your DB Path> --replSet <Replica Set Name could be any thing> & </li>
<li><span style="font-family: monospace;">You can also use configuration file to do that. More instruction here </span><span style="font-family: monospace;"><a href="http://docs.mongodb.org/manual/tutorial/deploy-replica-set/" target="_blank">http://docs.mongodb.org/manual/tutorial/deploy-replica-set/</a></span></li>
<li>Once Mongo DB is started you can add additional replica using following instruction </li>
</ul>
<div>
<script src="https://gist.github.com/yupadhyay/6b172ff9cf52a11fc8ef.js"></script>
</div>
<ul style="text-align: left;">
<li>Once Replica set is up, Now set Up AEM</li>
</ul>
<div>
<script src="https://gist.github.com/yupadhyay/d0ea8d57b35cd77fe03d.js"></script>
</div>
<ul>
<li>Then You can go to each Mongo Instance and check of data is coming using Mongo Log</li>
</ul>
<div>
<b><u>Convert Existing Mongo Instance:</u></b></div>
</div>
<div>
<br /></div>
<div>
<ul style="text-align: left;">
<li>Stop you AEM instance</li>
<li>Use Following instruction to convert Mongo to replica</li>
</ul>
<div>
<script src="https://gist.github.com/yupadhyay/6cd1e79d74174e9d1fc3.js"></script>
</div>
<ul style="text-align: left;">
<li>Once this is set Change AEM start script to add mongo replica instance as given in approach one </li>
<li>start your AEM instance</li>
<li>AEM should be part of replica set now</li>
</ul>
<div>
<br /></div>
</div>
<h2 style="text-align: left;">
<u>Backup and Restore</u></h2>
<div style="text-align: left;">
Please check <a href="https://docs.mongodb.org/v3.0/tutorial/backup-and-restore-tools/" target="_blank">https://docs.mongodb.org/v3.0/tutorial/backup-and-restore-tools/</a> for MongoDB instruction of backup and restore. </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Automated script can be found here: <a href="https://github.com/micahwedemeyer/automongobackup/blob/master/src/automongobackup.sh" target="_blank">https://github.com/micahwedemeyer/automongobackup/blob/master/src/automongobackup.sh</a> just put this script under /etc/cron.daily and you are set for backup.</div>
<h2 style="text-align: left;">
</h2>
<h2 style="text-align: left;">
<u>Some Common Questions</u></h2>
<h4 style="text-align: left;">
Should I set up my AEM author instance on MongoDB</h4>
<div style="text-align: left;">
Unless you have clustering requirement, I would not suggest to set up your author instance with MongoDB. Mainly because of administrative overhead.</div>
<div style="text-align: left;">
<br /></div>
<h4 style="text-align: left;">
Should I set up my AEM publish instance on MongoDB</h4>
<div style="text-align: left;">
Same as above, Unless you have a requirement which requires shared content generation I would suggest not to use MongoDB. With AEM communities, now you have an option to add Mongo Persistence for community feature at any time. Here is more detail <a href="https://docs.adobe.com/docs/en/aem/6-1/administer/communities/srp/msrp.html">https://docs.adobe.com/docs/en/aem/6-1/administer/communities/srp/msrp.html</a> and <a href="https://docs.adobe.com/docs/en/aem/6-1/administer/communities/srp/msrp/demo-mongo.html" target="_blank">https://docs.adobe.com/docs/en/aem/6-1/administer/communities/srp/msrp/demo-mongo.html</a></div>
<div style="text-align: left;">
<br /></div>
<h4 style="text-align: left;">
Should I store Blobs in MongoDB as well in AEM</h4>
<div style="text-align: left;">
It is not recommended to store Blob data with MongoDB. There are other options like, Local Storage, NAS, AWS you can use in that case. More detail <a href="https://docs.adobe.com/content/docs/en/aem/6-1/deploy/platform/aem-with-mongodb.html#AEM%20Configuration" target="_blank">https://docs.adobe.com/content/docs/en/aem/6-1/deploy/platform/aem-with-mongodb.html#AEM Configuration</a> and <a href="https://docs.adobe.com/docs/en/aem/6-1/deploy/platform/data-store-config.html" target="_blank">https://docs.adobe.com/docs/en/aem/6-1/deploy/platform/data-store-config.html</a></div>
<div style="text-align: left;">
<br /></div>
<h4 style="text-align: left;">
How can I secure my MongoDB deployment with AEM</h4>
<div style="text-align: left;">
Check documentation here <a href="https://blogs.adobe.com/security/2015/07/securely-deploying-mongodb-3-0.html">https://blogs.adobe.com/security/2015/07/securely-deploying-mongodb-3-0.html</a></div>
<h2 style="text-align: left;">
<u>Notes:</u></h2>
<div>
<br /></div>
<div>
1) Mongo Replication Only Provide High Availability (HA) it does not provide scalability. For scalability you need to use Sharding feature provided by Mongo. However I am not sure what would be best key to create shard on for Mongo. You can create Shard based on _id attribute. More information about sharding can be obtained here <a href="http://docs.mongodb.org/manual/sharding/" target="_blank">http://docs.mongodb.org/manual/sharding/</a> . If you are using Sharding I would suggest to use sharding with replication (Shard and then replicate shard instance) to provide both HA and scalability.</div>
<div>
<br /></div>
<div>
2) There are many feature available in Mongo Replication where you can make certain replica instance read only (Data Center replica), you can use this to avoid high latency across Data Center here is all configuration you can do on Mongo <a href="http://docs.mongodb.org/manual/administration/replica-set-member-configuration/" target="_blank">http://docs.mongodb.org/manual/administration/replica-set-member-configuration/</a></div>
<div>
<br /></div>
<div>
3) MongoDB recently released MMS <a href="https://mms.mongodb.com/" target="_blank">https://mms.mongodb.com/</a> to monitor and deploy Mongo Cluster easily. This will be useful if you are worried about administrative cost for Mongo </div>
<div>
<br /></div>
<div>
4) If you don't want to store large documents in Mongo feel free to use custom Data Store using instruction here <a href="http://jackrabbit.apache.org/oak/docs/osgi_config.html">http://jackrabbit.apache.org/oak/docs/osgi_config.html</a></div>
<div>
<br /></div>
<div>
5) Mongo Recently launched another feature of pluggable datastore. You can use this for faster read and write based on your requirement (For example Primary with high Write Enabled Storage Like SSD or something and read with cheap storage). More info here <a href="https://www.mongosoup.de/blog-entry/A-closer-look-at-pluggable-storage.html" target="_blank">https://www.mongosoup.de/blog-entry/A-closer-look-at-pluggable-storage.html</a> (Official Doc yet to come)<br />
<br />
6) Official AEM Documentation: <a href="https://docs.adobe.com/content/docs/en/aem/6-1/deploy/platform/aem-with-mongodb.html" target="_blank">https://docs.adobe.com/content/docs/en/aem/6-1/deploy/platform/aem-with-mongodb.html</a> </div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Finally .... Some more Mongo Command ...</div>
<div>
<br /></div>
<div>
<br /></div>
</div>
<script src="https://gist.github.com/yupadhyay/4a71d5ad759425e7b2ac.js"></script><br />
Special Thanks To <a href="https://www.linkedin.com/in/nemei" target="_blank">Nelson Mei</a> for Setting up POC for Mongo with AEM
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com18tag:blogger.com,1999:blog-5778419059463879376.post-86008161812963229032014-11-13T10:36:00.001-08:002014-11-13T10:36:53.334-08:00How to use impression Service In CQ/AEM<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<b><u>Use Case:</u></b><br />
<ol style="text-align: left;">
<li>You often have case where you want to use Impression service provided by CQ to do custom operation for example finding top 10 most viewed page or sorting all page based on there popularity.</li>
<li>It might possible that your impression data (Page Views) is in external system and then you want to import those data as impression in CQ to have more application context.</li>
<li>You want to aggregate all data across all publish instances.</li>
</ol>
<div>
<b><u>Solutions:</u></b></div>
<div>
<br />
<b><u>Approach 1:</u></b><br />
<br /></div>
Creating your Own Impression service<br />
<div>
<br /></div>
You can create your own impression service by extending com.day.crx.statistics.Entry here is example
<br />
<div>
Supporting class
<br /></div>
<script src="https://gist.github.com/yupadhyay/cbae58c8b066e7c0b02f.js"></script>
<br />
<div>
<br /></div>
<script src="https://gist.github.com/yupadhyay/7eb157f3adac332a7d07.js"></script>
<br />
<div>
</div>
You need to embed following dependency for this<br />
<script src="https://gist.github.com/yupadhyay/d62c6ef983ff57535477.js"></script>
Here is example of how you can use this service<br />
<br /></div>
</div>
<script src="https://gist.github.com/yupadhyay/81a87be56931d5280333.js"></script>
<script src="https://gist.github.com/yupadhyay/4799370542604c44eecf.js"></script>
Now you can import data from external system (GA, Site Catalyst, Kafka) and then populate it using this service to your instance.<br />
<br />
Once you are ready with all data you can use following service to use data,<br />
<br />
<br />
<script src="https://gist.github.com/yupadhyay/0ccbd243448cd5642145.js"></script>
<br />
Actual Implementation
<br />
<br />
<script src="https://gist.github.com/yupadhyay/2f7b4d7df39c9cfc2896.js"></script>
<br />
<b><u>Approach 2:</u></b><br />
<br />
You don't want to write your own service as mentioned in Approach 1 and use OOTB service available to you. Only problem with this is, You have multiple publish instance and some how you want to combine all data in to one so that you get accurate picture. It kind of tricky to get all data from all publish instance (through reverse replication) and then combine them on author and then push them over again. However you can use one instance to collect all stat data (king of single source of truth and then replicate it back to all instance every day)<br />
<br />
<br />
<ul style="text-align: left;">
<li>Make sure that you enable page view tracking by adding following line</li>
</ul>
<br />
<div>
<div>
<cq:include script="/libs/foundation/components/page/stats.jsp" /></div>
</div>
<div>
<ul style="text-align: left;">
<li>Then configure all publish instance to point to one DNS using following config (You can always override this under /apps)</li>
</ul>
<div>
/apps/wcm/core/config.publish/com.day.cq.wcm.core.stats.PageViewStatistics</div>
<div>
/apps/wcm/core/config.publish/com.day.cq.wcm.core.stats.PageViewStatisticsImpl</div>
<div>
</div>
<ul style="text-align: left;">
<li>make sure that pageviewstatistics.trackingurl is pointing to single domain (You need to create a domain, something like impression.mydomain.com that will be stand alone CQ instance to take all impression request)</li>
<li>Now you have consolidated page impression on one machine</li>
<li>You can easily write a schedular which will run every night and reverse replicate all data to author instance.</li>
<li>Once it is on author instance you can use replicator service to replicate to all other publish instance</li>
<li>Then you can use code mention in approach 1 to get popular resources.</li>
</ul>
<div>
<br /></div>
<div>
Note: You can always use GA or something to track data. This is more useful if you want to do something internally and not want top share data with GA.</div>
<div>
<br /></div>
<div>
As usual feel free to ask any question you have.</div>
<div>
<br /></div>
<div>
<br /></div>
</div>
<br />
<br />
<br /></div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com9tag:blogger.com,1999:blog-5778419059463879376.post-81088880063799358432014-11-07T14:23:00.002-08:002014-11-07T14:24:34.898-08:00How to make Instances SSL context aware in CQ/AEM<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Use Case:</b><br />
<br />
Most of the times we terminate SSL on load balancer or at dispatcher and communication to publish happen over http. In this case publish server is often not SSL aware and any request specific operations (For example relative path redirect or Link rewriting) happens over http. For example if you do something like request.sendRedirect("/somepath") from server it will get redirected to http://server-name/somepath or when you will do request.isSecure() it will return false. Operations like externalizer.externalLink(resolver, "mydomain", "/my/page") + ".html"; will also return http version of link.<br />
<br />
<b>Solution:</b><br />
<br />
<b>Option 1:</b><br />
<br />
Let all links be http and then do force redirect on dispatcher or Load Balancer. For dispatcher rule can be as simple as this,<br />
<br />
RewriteCond %{HTTPS} off<br />
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [L,R=301]<br />
<br />
<b>Issue:</b><br />
<br />
<ul style="text-align: left;">
<li>Not SEO friendly (Unless it is relative link). </li>
<li>Can not embed as portlet or Iframe (Cross Site include error) over https.</li>
</ul>
<div>
<br /></div>
<div>
<b>Option 2: </b></div>
<div>
<br /></div>
<div>
Use SSL filter from Felix HTTP services <a href="http://felix.apache.org/documentation/subprojects/apache-felix-http-service.html#using-the-ssl-filter" target="_blank">http://felix.apache.org/documentation/subprojects/apache-felix-http-service.html#using-the-ssl-filter</a></div>
<div>
<br /></div>
<div>
If filter is configured, it looks for header configured in configuration and if header value matches configured value context on publish is considered secure and request.isSecure() will return true.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZIuNxsIpfijDBIlIMjMBqnQJyiqwFZfzH8eLfbX2nBVKVFxxXrV37IG6G3BqN7E6ynv_kuUM0_dPzJ34m8XKfpCDM9ac4hrmmC-jqLXD1oswQSXC8S3QvgCqF2jPM2GQ5OAuiEV3_DME/s1600/ssl_configuration_felix.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZIuNxsIpfijDBIlIMjMBqnQJyiqwFZfzH8eLfbX2nBVKVFxxXrV37IG6G3BqN7E6ynv_kuUM0_dPzJ34m8XKfpCDM9ac4hrmmC-jqLXD1oswQSXC8S3QvgCqF2jPM2GQ5OAuiEV3_DME/s1600/ssl_configuration_felix.png" height="165" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_MhywJ0Q0DqfjVC_GjSx9HTjuHNlXemKP2B8_-w3RKsx-Y4hX5DbIhUdLRb3KZMTVOqtd08M8i09q6UgBhGxdq18m_CSEeu6WRY0gC2feHQj9iYqqeswCMaRiYX0eYvv-OWAsWkB1_VU/s1600/ssl_felix_bundle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_MhywJ0Q0DqfjVC_GjSx9HTjuHNlXemKP2B8_-w3RKsx-Y4hX5DbIhUdLRb3KZMTVOqtd08M8i09q6UgBhGxdq18m_CSEeu6WRY0gC2feHQj9iYqqeswCMaRiYX0eYvv-OWAsWkB1_VU/s1600/ssl_felix_bundle.png" height="36" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
In above case if X-Forwarded-SSL is present with value on then servlet context is secure.</div>
<div>
<br /></div>
<div>
<b>Note:</b> This might not work in version latest CQ version. You can build your own version from trunk <a href="https://github.com/apache/felix/tree/trunk/http/sslfilter" target="_blank">https://github.com/apache/felix/tree/trunk/http/sslfilter </a>or from <a href="http://svn.apache.org/repos/asf/felix/trunk/http/sslfilter/" target="_blank">http://svn.apache.org/repos/asf/felix/trunk/http/sslfilter/</a></div>
<div>
<br /></div>
<div>
One working version of file can be downloaded from <a href="https://drive.google.com/file/d/0B6solO-ErCt7dGhGd3IzdUI4X3M/view?usp=sharing" target="_blank">here</a></div>
<div>
<br /></div>
<div>
As usual let me know if you have any question. Special thanks to Shenghao Huang from LinkedIn for finding this.</div>
<div>
<br /></div>
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com4tag:blogger.com,1999:blog-5778419059463879376.post-16094524710208828712014-11-05T09:54:00.001-08:002016-02-17T14:04:48.094-08:00How to use Sling Models in CQ5.6<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Use Case:</b> Use Sling Model in CQ5.6<br />
<br />
<b>Background:</b> Sling model <a href="http://sling.apache.org/documentation/bundles/models.html" target="_blank">http://sling.apache.org/documentation/bundles/models.html</a> brings powerful way of mapping your resources to Java Objects (Beans) . It is supported OOTB in CQ6 however we can use it in CQ5.6 as well.<br />
<br />
<b>Solution:</b><br />
<br />
First add sling models as dependency in your code (In Parent pom using dependency manager is preferred)<br />
<br />
<script src="https://gist.github.com/yupadhyay/9b085c07ff59de24fe1c.js"></script>
Then update your reactor pom (Which actually creates your CQ package using content-package-<span class="s1">maven</span>-<span class="s1">plugin) you need to add following as dependency and then embed them in to your project (If install path for system is not present you can use any other path you want)</span>
<script src="https://gist.github.com/yupadhyay/86199243a6ec506ee139.js"></script>
<br />
<br />
Thats it .. Models are available as service in your OSGI environment.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjF0nHSxf_laa7pGwIj4TXBW1tEiF7D9dAkOAjnJJ3MX2WVcoW3SFvmW9qV6_vggWgHOfAO6rO7FscCqZhOHKlFvjMiN4zNleUubwFqWTTIcEGmm5eTiYg02MCY2oPxeSJciq7nuL8EoLE/s1600/Screen+Shot+2014-11-05+at+9.33.38+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="32" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjF0nHSxf_laa7pGwIj4TXBW1tEiF7D9dAkOAjnJJ3MX2WVcoW3SFvmW9qV6_vggWgHOfAO6rO7FscCqZhOHKlFvjMiN4zNleUubwFqWTTIcEGmm5eTiYg02MCY2oPxeSJciq7nuL8EoLE/s1600/Screen+Shot+2014-11-05+at+9.33.38+AM.png" width="640" /></a></div>
<br />
<br />
To use model go ahead and create your own bundle and them add these as dependency. You should be able to write, deploy and run code against model. Note that you might have to make these model available to osgi using Sling-Model-Packages<br />
<br />
<br />
<script src="https://gist.github.com/yupadhyay/387789fc1bb96faf1a74.js"></script>
<br />
Once model is deployed correctly you should be able to see them under sling-model tab in status in felix console or by going to HOST:PORT/system/console/status-slingmodels<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZCNnNaYp-nLgCXhERvbZQRrT85_n4lptWSXNLsbgv5cEYWOqq124VW48Foh5h-FODlM0gdINTCt0DUiQA9Av9mNxg17KBExQmz6-qlZCHtZvk6qF2M7vB9Vh8LZ5E_Gind3tV4eG7a_0/s1600/sling-model-tab.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZCNnNaYp-nLgCXhERvbZQRrT85_n4lptWSXNLsbgv5cEYWOqq124VW48Foh5h-FODlM0gdINTCt0DUiQA9Av9mNxg17KBExQmz6-qlZCHtZvk6qF2M7vB9Vh8LZ5E_Gind3tV4eG7a_0/s1600/sling-model-tab.png" width="150" /></a></div>
<br />
<br />
Some example code using models
<br />
<script src="https://gist.github.com/yupadhyay/59bedff99230e9824fc2.js"></script>
<br />
<h3 style="text-align: left;">
<b>Some common How to</b></h3>
<h4 style="text-align: left;">
<b>How can I inject services in Sling Model</b></h4>
by using annotation @OSGIService Or Using Injector @Inject @Source("osgi-service")<b> </b><br />
<br />
Example:<br />
<br />
<span style="color: blue;">@OSGIService</span><br />
<span style="color: blue;">MyService myService</span><br />
<br />
<span style="color: blue;">@Inject @Source("osgi-service")</span><br />
<span style="color: blue;">MyService myService </span><b><br /></b><br />
<br />
<h4 style="text-align: left;">
<b>How Can I Inject Sling Object in Sling Model</b></h4>
by using annotation @SlingObject Or Using Injector @Inject @Source("sling-object")<b> </b><br />
<br />
Example:<br />
<br />
<span style="color: blue;">@SlingObject</span><br />
<span style="color: blue;">ResourceResolver resourceResolver</span><br />
<br />
<span style="color: blue;">@Inject @Source("sling-object")</span><br />
<span style="color: blue;">ResourceResolver resourceResolver</span><br />
<br />
<br />
<h4 style="text-align: left;">
<b>How Can I get access to property if adapting through Sling Request</b></h4>
If you are adapting your model to sling request you might not have access to property by just doing @Inject. You have to use @Via in that case. Note that you can use all other annotation here like @Named and all. Here is example<b> </b><br />
<br />
<pre style="-webkit-text-stroke-width: 0px; color: black; font-size: 13.3333px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 18.6667px; margin: 0px; orphans: auto; overflow: auto; padding: 0px; text-align: start; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px;"><span class="nd" style="color: #0000dd;">@Model</span><span class="o">(</span><span class="n" style="color: #0000dd;">adaptables</span><span class="o">=</span><span class="n" style="color: #0000dd;">SlingHttpServletRequest</span><span class="o">.</span><span class="na" style="color: #0000dd;">class</span><span class="o">)</span>
<span class="kd" style="color: #880000;">public</span> <span class="kd" style="color: #880000;">interface</span> <span class="nc" style="color: #0000dd;">MyModel</span> <span class="o">{</span> </pre>
<pre style="-webkit-text-stroke-width: 0px; color: black; font-size: 13.3333px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 18.6667px; margin: 0px; orphans: auto; overflow: auto; padding: 0px; text-align: start; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px;"> </pre>
<pre style="-webkit-text-stroke-width: 0px; color: black; font-size: 13.3333px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 18.6667px; margin: 0px; orphans: auto; overflow: auto; padding: 0px; text-align: start; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px;"> <span class="nd" style="color: #0000dd;">@Inject</span> <span class="nd" style="color: #0000dd;">@Via</span><span class="o">(</span><span class="s" style="color: #008800;">"resource"</span><span class="o">)</span>
<span class="n" style="color: #0000dd;">String</span> propertyName<span class="o">;</span>
<span class="o">}</span></pre>
<br />
<h4 style="text-align: left;">
<b>How Can I use Sling Tag Library with Sling Model</b></h4>
You can use <sling:adaptTo ... /> or ${sling:adaptTo ...} as mentioned in <a href="https://sling.apache.org/documentation/bundles/models.html">https://sling.apache.org/documentation/bundles/models.html</a> and <a href="https://sling.apache.org/documentation/bundles/sling-scripting-jsp-taglib.html">https://sling.apache.org/documentation/bundles/sling-scripting-jsp-taglib.html</a> .In 5.6 you might have to change global.jsp to use<br />
<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling" %><br />
instead of<br />
<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0" %><br />
<br />
<h4 style="text-align: left;">
<b>How Can I provide default value to property in Sling Model</b></h4>
By using @Default Annotation<b> . </b>Here is example<br />
<br />
A default value can be provided (for Strings & primitives) and Array: <br />
<div class="codehilite" style="-webkit-text-stroke-width: 0px; background-color: #f4f4f4; border: 1px solid rgb(221, 221, 221); color: black; font-family: Tahoma, Arial, sans-serif; font-size: 13.3333px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 18.6667px; margin-bottom: 0.5em; margin-top: 0.5em; orphans: auto; padding: 0.5em; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<pre style="margin: 0px; overflow: auto; padding: 0px;"><span class="nd" style="color: #0000dd;">@Model</span><span class="o">(</span><span class="n" style="color: #0000dd;">adaptables</span><span class="o">=</span><span class="n" style="color: #0000dd;">Resource</span><span class="o">.</span><span class="na" style="color: #0000dd;">class</span><span class="o">)</span>
<span class="kd" style="color: #880000;">public</span> <span class="kd" style="color: #880000;">class</span> <span class="nc" style="color: #0000dd;">MyModel</span> <span class="o">{</span>
<span class="nd" style="color: #0000dd;">@Inject</span> <span class="nd" style="color: #0000dd;">@Default</span><span class="o">(</span><span class="n" style="color: #0000dd;">values</span><span class="o">=</span><span class="s" style="color: #008800;">"defaultValue"</span><span class="o">)</span>
<span class="kd" style="color: #880000;">private</span> <span class="n" style="color: #0000dd;">String</span> <span class="n" style="color: #0000dd;">name</span><span class="o">;</span> </pre>
<pre style="margin: 0px; overflow: auto; padding: 0px;"> <span class="nd" style="color: #0000dd;">@Inject</span> <span class="nd" style="color: #0000dd;">@Default</span><span class="o">(</span><span class="n" style="color: #0000dd;">intValues</span><span class="o">={</span><span class="mi">1</span><span class="o">,</span><span class="mi">2</span><span class="o">,</span><span class="mi">3</span><span class="o">,</span><span class="mi">4</span><span class="o">})</span>
<span class="kd" style="color: #880000;">private</span> <span class="kt" style="color: #880000;">int</span><span class="o">[]</span> <span class="n" style="color: #0000dd;">integers</span><span class="o">;</span> </pre>
<pre style="margin: 0px; overflow: auto; padding: 0px;"><span class="o">}</span>
</pre>
</div>
<br />
<h4 style="text-align: left;">
<b>How Can I inject child resource as Model in Sling Model </b></h4>
This can be done by Injecting a model in other model class. Here is example<b><br /></b><br />
<br />
<div class="codehilite" style="-webkit-text-stroke-width: 0px; background-color: #f4f4f4; border: 1px solid rgb(221, 221, 221); color: black; font-family: Tahoma, Arial, sans-serif; font-size: 13.3333px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 18.6667px; margin-bottom: 0.5em; margin-top: 0.5em; orphans: auto; padding: 0.5em; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<pre style="margin: 0px; overflow: auto; padding: 0px;"><span class="nd" style="color: #0000dd;">@Model</span><span class="o">(</span><span class="n" style="color: #0000dd;">adaptables</span><span class="o">=</span><span class="n" style="color: #0000dd;">Resource</span><span class="o">.</span><span class="na" style="color: #0000dd;">class</span><span class="o">)</span>
<span class="kd" style="color: #880000;">public</span> <span class="kd" style="color: #880000;">interface</span> <span class="nc" style="color: #0000dd;">MyModel</span> <span class="o">{</span>
<span class="nd" style="color: #0000dd;">@Inject</span>
<span class="n" style="color: #0000dd;">ImageModel</span> <span class="nf" style="color: #0000dd;">getImage</span><span class="o">();</span>
<span class="o">}</span>
<span class="nd" style="color: #0000dd;">@Model</span><span class="o">(</span><span class="n" style="color: #0000dd;">adaptables</span><span class="o">=</span><span class="n" style="color: #0000dd;">Resource</span><span class="o">.</span><span class="na" style="color: #0000dd;">class</span><span class="o">)</span>
<span class="kd" style="color: #880000;">public</span> <span class="kd" style="color: #880000;">interface</span> <span class="nc" style="color: #0000dd;">ImageModel</span> <span class="o">{</span>
<span class="nd" style="color: #0000dd;">@Inject</span>
<span class="n" style="color: #0000dd;">String</span> <span class="nf" style="color: #0000dd;">getPath</span><span class="o">();</span>
<span class="o">}</span>
</pre>
</div>
<br />
<i>When a resource is adapted to MyModel, a child resource named image is automatically adapted to an instance of ImageModel</i><br />
<br />
<b>Note:</b> Sling model version number can change as it evolves in future. Make sure that you update model dependencies version accordingly. You can also use Sling testing framework to test sling model which is pretty cool as well. There is also an example of deployable Model package <a href="https://github.com/Adobe-Consulting-Services/com.adobe.acs.bundles.sling-models" target="_blank">https://github.com/Adobe-Consulting-Services/com.adobe.acs.bundles.sling-models</a> which you can use.<br />
<br />
As usual feel free to give your comment and feedback and let me know if you want me to add something else here.<br />
<br />
<br /></div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com6tag:blogger.com,1999:blog-5778419059463879376.post-36669949734657922652014-10-16T12:58:00.001-07:002014-10-20T10:08:34.842-07:00How to Connect to External Data Source (Teradata / MySQL / Oracle) in CQ / AEM<div dir="ltr" style="text-align: left;" trbidi="on">
<b><u>Use Case:</u></b> Connect to external datasource using CQ<br />
<br />
<b><u>Solution:</u></b><br />
<br />
<b>1) My SQL</b><br />
<br />
Step 1: Create OSGI version of mysql Jar file<br />
<br />
<ul style="text-align: left;">
<li>Download MySQL JDBC Driver From <a href="http://dev.mysql.com/downloads/connector/j" target="_blank">http://dev.mysql.com/downloads/connector/j </a></li>
<li>Open eclipse and select file -> New -> Other -> Plugin development -> Plug-in from existing Jar Archive</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEict2u2o9x_kR-AM7rkSpHQiRfFkyXC03Six3ApFNN9tMWbup36CkF7SKbiZcWCe04IH931M2gbE8v8wXDCPD8sGCa4jO-l8038GZGxrCn1qt1RFsWhvdw1NSmUcVt5quVtQM4wjUda_78/s1600/mysql_plugin_project.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEict2u2o9x_kR-AM7rkSpHQiRfFkyXC03Six3ApFNN9tMWbup36CkF7SKbiZcWCe04IH931M2gbE8v8wXDCPD8sGCa4jO-l8038GZGxrCn1qt1RFsWhvdw1NSmUcVt5quVtQM4wjUda_78/s1600/mysql_plugin_project.png" height="275" width="320" /></a></div>
<div>
<br /></div>
<ul style="text-align: left;">
<li>Click next and then select add external. Select jar file you downloaded above and select next</li>
<li> Give Project Name -> Select Location -> Make sure that Analyze Library Content is checked -> In Target Platform select an OSGI framework -> from drop down select standard -> Check unzip jar file and update reference -> click finish</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQWTqc5I6ngXUiC17b1-FwOhXUTTu2XRPktyYFZFWRNz5LlELs5G7PKVsGFGioFzKtq5337jErup2-fsP9Ac09JmIHi1d-XJN6fbVSVUoTwSexjqq3Yt2LLmKaKqmjCj-tLSGWw7bIbo4/s1600/MySql_osgi_bundle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQWTqc5I6ngXUiC17b1-FwOhXUTTu2XRPktyYFZFWRNz5LlELs5G7PKVsGFGioFzKtq5337jErup2-fsP9Ac09JmIHi1d-XJN6fbVSVUoTwSexjqq3Yt2LLmKaKqmjCj-tLSGWw7bIbo4/s1600/MySql_osgi_bundle.png" height="320" width="264" /></a></div>
<div>
<br /></div>
<ul style="text-align: left;">
<li>An Plugin Development prospective will open </li>
<li>Click on export tab and make sure that all dependencies are exported (If they are not there, Click on add then select all)</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3Yx4ThuWd_mLAqQN9B4ENEFIdvsvni2ohDk41ol616c85excYmcO9DvcdA0PbdlqhqT8UVVnikcLoFVsgs3lqTdGLyql4JDemeNYP8BOMplCwSFUOyZiT5H1o-_lzG41oaVlcUr07Ae8/s1600/Import_export_Mysql_osgi.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3Yx4ThuWd_mLAqQN9B4ENEFIdvsvni2ohDk41ol616c85excYmcO9DvcdA0PbdlqhqT8UVVnikcLoFVsgs3lqTdGLyql4JDemeNYP8BOMplCwSFUOyZiT5H1o-_lzG41oaVlcUr07Ae8/s1600/Import_export_Mysql_osgi.png" height="320" width="293" /></a></div>
<div>
<br /></div>
<ul style="text-align: left;">
<li>Click on Dependencies and make sure that Imported packages are there. If it is not there click on MENIFEST.MF tab and then add following import statement </li>
<li>Once all import and export statement is added your MENIFEST.MF will have following data</li>
</ul>
<script src="https://gist.github.com/yupadhyay/e0ce7b850462152d1787.js"></script>
<br />
<ul style="text-align: left;">
<li>Then right click on your project and then select export </li>
<li>Select Deployable Deployable plug-in and fragments</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjbWvLkEDsEwPX4Qw2arIFd54ENXkgMAyqPwcTp1FR3hfIqQqzUcOPtEAtBGI70YORkQ57rKmSQUudCHORPl1livBHdUEVfABsZdemXJq_twq64f_VNBP3zauJtAuDqGOMp2xq5KNiCxQ/s1600/deployment_plugin_mysql_jar.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjbWvLkEDsEwPX4Qw2arIFd54ENXkgMAyqPwcTp1FR3hfIqQqzUcOPtEAtBGI70YORkQ57rKmSQUudCHORPl1livBHdUEVfABsZdemXJq_twq64f_VNBP3zauJtAuDqGOMp2xq5KNiCxQ/s1600/deployment_plugin_mysql_jar.png" height="275" width="320" /></a></div>
<div>
<br /></div>
<ul style="text-align: left;">
<li>Click Next and select your plug-in </li>
<li>From Directory section select location where you want to upload.</li>
<li>Click finish. This will store OSGI jar in to location you selected.</li>
<li>Once you have MySQL Osgi bundle. Install that bundle either using felix console or adding it through deployment process</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj76CpY_PeN5QqlMnVRLGHW9cpqlLSrMuJRyW93VIAukAcVFejJL71TMPKPOEVynHbkfXrCcYrwajrHxNsFHOLXmRPBheGfky7yGKMDlfsjhJHRd-IFXv9fUgzz1AOJ4R0Hbkm0w4koAsA/s1600/mysql_osgi_bundle_felix.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj76CpY_PeN5QqlMnVRLGHW9cpqlLSrMuJRyW93VIAukAcVFejJL71TMPKPOEVynHbkfXrCcYrwajrHxNsFHOLXmRPBheGfky7yGKMDlfsjhJHRd-IFXv9fUgzz1AOJ4R0Hbkm0w4koAsA/s1600/mysql_osgi_bundle_felix.png" height="211" width="400" /></a></div>
<div>
<br /></div>
<ul style="text-align: left;">
<li>If you are getting error saying javax.Naming not getting resolved then you have to add following line in sling.properties under crx-quickstart folder</li>
</ul>
<span class="s1">org.osgi.framework.bootdelegation</span><span class="s2">= </span>javax.naming.*, ${org.apache.sling.launcher.bootdelegation}<br />
<ul style="text-align: left;">
<li>Once bundle is up is running, You need to go to felix osgi config. Search For JDBC connection pool and then click '+'</li>
<li>Fill all the information about your datasource</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6GaBuMy-7fRGJBYqQ_kSVUh7iKg0rOrWI9heGhm6wTeXe4vQtL1TxlG5CH8L9dx78fYk34VZQcGaeiIFWzd13GzMGEy_GYlqdptjDGMKFyuiF_8SuQG-aMuLrEYfA2ylrvbiTIirFfeI/s1600/CQ_OSGI_MySQL_Config.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6GaBuMy-7fRGJBYqQ_kSVUh7iKg0rOrWI9heGhm6wTeXe4vQtL1TxlG5CH8L9dx78fYk34VZQcGaeiIFWzd13GzMGEy_GYlqdptjDGMKFyuiF_8SuQG-aMuLrEYfA2ylrvbiTIirFfeI/s1600/CQ_OSGI_MySQL_Config.png" height="332" width="640" /></a></div>
<div>
<br /></div>
<ul style="text-align: left;">
<li>Go to your application logic and test your code</li>
</ul>
<script src="https://gist.github.com/yupadhyay/eaf86274c6b49060714a.js"></script>
<br />
<div>
<br />
If you are having trouble creating osgi version of mysql jar file, You can download it from <a href="https://drive.google.com/file/d/0B6solO-ErCt7R1M5b1Z3Ulg4ZzQ/view?usp=sharing" target="_blank">here</a><br />
<br />
<b><u>2) Teradata</u></b><br />
<ul style="text-align: left;">
<li>All the steps for Teradata will remain same except you need to create teradata OSGI bundle using Teradata JDBC connector.</li>
<li>First Download teradatajdbc connector from here <a href="https://code.google.com/p/kyunra-java/downloads/detail?name=terajdbc4.jar" target="_blank">https://code.google.com/p/kyunra-java/downloads/detail?name=terajdbc4.jar</a></li>
<li>Then Download tdconfig jar from here <a href="https://code.google.com/p/kyunra-java/downloads/detail?name=tdgssconfig.jar" target="_blank">https://code.google.com/p/kyunra-java/downloads/detail?name=tdgssconfig.jar</a></li>
<li>Follow above steps to create osgi version of jar file (Everything will remain same except this time you need to select two jar file for creating osgi version of it)</li>
<li>Your Final MENIFEST.MF will look like this</li>
</ul>
<script src="https://gist.github.com/yupadhyay/77e828be23aaccab47f1.js"></script>
<br />
<ul style="text-align: left;">
<li>Upload final jar file in CQ, make sure that it is active</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj76CpY_PeN5QqlMnVRLGHW9cpqlLSrMuJRyW93VIAukAcVFejJL71TMPKPOEVynHbkfXrCcYrwajrHxNsFHOLXmRPBheGfky7yGKMDlfsjhJHRd-IFXv9fUgzz1AOJ4R0Hbkm0w4koAsA/s1600/mysql_osgi_bundle_felix.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj76CpY_PeN5QqlMnVRLGHW9cpqlLSrMuJRyW93VIAukAcVFejJL71TMPKPOEVynHbkfXrCcYrwajrHxNsFHOLXmRPBheGfky7yGKMDlfsjhJHRd-IFXv9fUgzz1AOJ4R0Hbkm0w4koAsA/s1600/mysql_osgi_bundle_felix.png" height="337" width="640" /></a></div>
<div>
<br /></div>
<ul style="text-align: left;">
<li>Open OSGI config to create config for teradata connection pool</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe5qQ5DzVlISf778evaFg7s2HKpfneeuNvRwNFvFd_28MiIJzFwiydzBj0h_CxUR3NvSbZo5le7NtZ8WNzrCKE1lgDWhkK7b1Mw83vHXxnd771Q8RWxxNPyjWYSp8c6BWKlZpc_86xt2Y/s1600/teradata_connection_felix_console_cq.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe5qQ5DzVlISf778evaFg7s2HKpfneeuNvRwNFvFd_28MiIJzFwiydzBj0h_CxUR3NvSbZo5le7NtZ8WNzrCKE1lgDWhkK7b1Mw83vHXxnd771Q8RWxxNPyjWYSp8c6BWKlZpc_86xt2Y/s1600/teradata_connection_felix_console_cq.png" height="332" width="640" /></a></div>
<div>
<br /></div>
<ul style="text-align: left;">
<li>You can then test it using same code (Just use teradata data source)</li>
</ul>
<script src="https://gist.github.com/yupadhyay/eaf86274c6b49060714a.js"></script>
<br />
<div>
<br />
You can also download OSGI version of teradata jar file from <a href="https://drive.google.com/file/d/0B6solO-ErCt7LTljZnZyWWJqQk0/view?usp=sharing" target="_blank">here</a><br />
<br />
Note: If You want to call instance of your Connection from Java class (Not from service) You can do something like this,<br />
<br />
<br /></div>
</div>
<ol style="text-align: left;">
</ol>
</div>
<script src="https://gist.github.com/yupadhyay/ea18e4b2fd3ac11528a7.js"></script>Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com11tag:blogger.com,1999:blog-5778419059463879376.post-89435270799400438202014-08-28T15:32:00.001-07:002016-01-29T14:46:14.882-08:00How to Use Sessions and Resource Resolver through Service Authentication In AEM6<div dir="ltr" style="text-align: left;" trbidi="on">
<div>
<b><u>Use Case:</u></b> As per <a href="http://sling.apache.org/documentation/the-sling-engine/service-authentication.html" target="_blank">http://sling.apache.org/documentation/the-sling-engine/service-authentication.html</a> and <a href="http://docs.adobe.com/content/docs/en/aem/6-0/develop/ref/diff-previous/changes/changes-summary.html" target="_blank">http://docs.adobe.com/content/docs/en/aem/6-0/develop/ref/diff-previous/changes/changes-summary.html</a> using admin session and admin resource resolver through ResourceresolverFactory is now deprecated. Using Service based Authentication for Resourceresolver and Respository session solves problem like (Directly From Sling Doc),</div>
<div>
<ul style="text-align: left;">
<li>Prevent over-use and abuse of administrative ResourceResolvers and/or JCR Sessions</li>
<li>Allow services access to ResourceResolvers and/or JCR Sessions without requiring to hard-code or configure passwords</li>
<li>Allow services to use service users which have been specially configured for service level access (as is usually done on unixish systems)</li>
<li>Allow administrators to configure the assignment of service users to services</li>
</ul>
</div>
<div>
<br /></div>
<div>
<b><u>Solution:</u></b></div>
<div>
<br />
<b>NOTE:</b> Use Service Accounts for alice and bob users [jcr:primaryType=rep:SystemUser] instead of regular accounts.<br />
<br /></div>
<div>
Lets see we have two user "alice" and "bob", with following property,</div>
<div>
<ul style="text-align: left;">
<li>"alice" only have READ access to document under /content/somepath path</li>
<li>"bob" has both read and write access to document under /content/somepath path</li>
</ul>
</div>
<div>
Now we have two service "ReadService" and "WriteService", with following property</div>
<div>
<ul style="text-align: left;">
<li>ReadService should only be allowed to read anything under /content/somepath path</li>
<li>WriteService should be allowed for both read and write under /content/somepath path</li>
</ul>
</div>
<div>
<br /></div>
<div>
Assume your package name is <b>blog.wemblog.com</b></div>
<div>
<br /></div>
<div>
<b><u>Step 1:</u></b> Create ReadService and WriteService using resourceResolver Or adminSession using new Authentication Service based API</div>
<script src="https://gist.github.com/yupadhyay/8aa96bcd7ae3a6ba3829.js"></script>
<b><u>Step 2:</u></b> Create ReadService same way<br />
<script src="https://gist.github.com/yupadhyay/e33a7522591c090a039c.js"></script>
<b><u>Step 3:</u></b> Update org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl config by creating osgi:config node under <b>/apps/<your-apps>/config.<Place where you want to run this>/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml</b> you can directly go to osgi config through Felix console and change this as well look for “<b>Apache Sling Service User Mapper Service</b>” for that.<br />
<div>
<br /></div>
<div>
Syntax for service mapping to user is <i>‘serviceName [ ":" subServiceName ] “=” username’.</i></div>
<div>
and Entry of OSGI config will look like this,</div>
<script src="https://gist.github.com/yupadhyay/3392da46d1d60cb9f9dd.js"></script>
<br />
<div>
After installing the bundle and configuration and code, You would see something like this in log</div>
<div>
<br /></div>
<div>
*INFO* blog.wemblog.com.ReadServiceImpl alice</div>
<div>
*INFO* blog.wemblog.com.ReadServiceImpl <node type of somepath></div>
<div>
<br /></div>
<div>
*INFO* blog.wemblog.com.WriteServiceImpl bob</div>
<div>
*INFO* blog.wemblog.com.WriteServiceImpl <node type of somepath></div>
<div>
*INFO* blog.wemblog.com.WriteServiceImpl Successfully saved</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
If you need to use admin session for the configuration you can do something like blog.wemblog.com:WriteService=admin in osgi config above. Good practice is to have these session based on groups depending upon which group have access to what service.</div>
<div>
<br /></div>
<div>
You might need following dependencies in your POM for api to be available</div>
<script src="https://gist.github.com/yupadhyay/babbb1fb2d633898590e.js"></script>
<br />
<div>
<span style="color: blue;"><br /></span></div>
<div>
Please check http://stackoverflow.com/questions/31350548/resourceresolverfactory-getserviceresourceresolver-throws-exception-in-aem-6-1 with some of the changes in AEM6.1 of how to use this. <br />
<br />
As always feel free to ask any question you might have.</div>
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com6tag:blogger.com,1999:blog-5778419059463879376.post-51448037393240944762014-07-30T11:05:00.000-07:002014-11-05T09:56:46.450-08:00How to Remove White Space From Generated HTML In CQ (Or In general)<div dir="ltr" style="text-align: left;" trbidi="on">
<b><u>Use Case:</u></b> There are a lot of white spaces in generated Output of CQ increasing size of page and decreasing load time.<br />
<br />
<b><u>Solutions:</u></b><br />
<br />
<b><u>Option 1:</u></b> You can use trimDirectiveWhitespaces directive in jsp response. something like<br />
<br />
<%@page trimDirectiveWhitespaces="true"%><br />
<br />
<b><u>Problem:</u></b> Using this directive can cause white space to be removed from taglibs for same property. To avoid this issue make sure that you manually add space there. For example if you have tag lib like <Something class="${test1} ${test2}" class2="test"> replace it with <Something class="${test1} ${space} ${test2}" class2="test"> where ${space} is actual space " "<br />
This approach might not work with Slighly framework.<br />
<br />
<b><u>Option 2:</u></b> Use %><% tags to start and end scriplets tag and in between html tag<br />
<br />
<b><u>Problem: </u></b>Code very hard to read and not pretty.<br />
<br />
<div style="text-align: left;">
<b><i><u><span style="font-family: Times, Times New Roman, serif;">Option 3:</span> </u></i></b>Create your own tag library and using html parser remove white spaces during run time. for that check <a href="http://www.cqblueprints.com/tipsandtricks/jsp-custom-tag-lib.html" target="_blank">http://www.cqblueprints.com/tipsandtricks/jsp-custom-tag-lib.html</a></div>
<br />
And code to remove White space would be<br />
<br />
<script src="https://gist.github.com/yupadhyay/0e54657d7993c7448572.js"></script>
<br />
<br />
<b><u>Problem:</u></b> Maintenance of your own tag library. Can Miss Some condition. Have to wrap up your code with tag lib.<br />
<br />
<b><u>Option 4 (Preferred):</u></b> Use Google Page Speed Module at apache.<br />
<br />
Link to Module: <a href="https://developers.google.com/speed/pagespeed/module" target="_blank">https://developers.google.com/speed/pagespeed/module</a><br />
Link to All available Filters for Module: <a href="https://developers.google.com/speed/pagespeed/module/config_filters" target="_blank">https://developers.google.com/speed/pagespeed/module/config_filters</a><br />
Instruction of how to install and build: <a href="https://developers.google.com/speed/pagespeed/module/download" target="_blank">https://developers.google.com/speed/pagespeed/module/download</a><br />
<br />
<b>Steps to integrate it in Dispatcher:</b><br />
<b><br /></b>
1) Create Apache module using step above. This will give you <a href="https://drive.google.com/a/wemblog.com/file/d/0B6solO-ErCt7SW9sYU1oZHFUck0/edit?usp=sharing" target="_blank">mod_pagespeed.so</a> and <a href="https://drive.google.com/a/wemblog.com/file/d/0B6solO-ErCt7RGhIMDNaT1ZVRTg/edit?usp=sharing" target="_blank">mod_pagespeed_ap24.so</a><br />
<br />
2) Move this file to <Apache location>/modules<br />
<br />
3) Change permission (to daemon:daemon (Or Your Apache User)) and permission level (766) using chown and chmod command<br />
<br />
4) Open conf/httpd.conf and add following line (If some include is already there ignore that)<br />
Include <Apache Location>/conf/pagespeed.conf<br />
<br />
5) Create a folder called <Doc Root>/mod_pagespeed/<br />
<br />
6) Add <a href="https://drive.google.com/file/d/0B6solO-ErCt7ZDNRdV9XYVRUNmc/edit?usp=sharing">pagespeed.conf</a> under <Apache Location>/conf<br />
<span style="color: red;">* Make sure that All paths mentioned in conf file exist.</span><br />
<span style="color: red;"><br /></span>
7) Restart Apache<br />
<br />
<br />
<b><u>Problem</u></b>:<br />
1) Only Apache module is available. If you are using IIS or any other web server then there is no module yet.<br />
2) You might have to do build distribution for your own OS if above module build does not work (One attached here is build for Red Hat Linux).<br />
3) When you upgrade your Apache make sure to upgrade your module as well. If there is no distribution for newer version of apache, then also you are out of luck.<br />
<br />
<br />
<span style="color: red;"><b><u>Note</u></b>: Test above methods before using them in production. Feel free to ask any question you have.</span></div>Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com0tag:blogger.com,1999:blog-5778419059463879376.post-11576133471296415372014-07-28T09:50:00.001-07:002015-10-07T12:27:53.295-07:00How to include all CQ dependencies in CQ6<div dir="ltr" style="text-align: left;" trbidi="on">
<b><u>Use case:</u></b> Prior to CQ6 you have to add dependencies for each class you are using in your pom.xml, Way to find dependencies was (Maven org http://mvnrepository.com or using adobe central http://repo.adobe.com/nexus/content/groups/public through dependency finder HOST:PORT/system/console/depfinder). With CQ6 now all dependencies are provided through one artifactID.<br />
<br />
<b><u>Prerequisite</u></b>: <a href="http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html" target="_blank">Maven</a>, <a href="http://docs.adobe.com/docs/en/aem/6-0/develop/how-tos/ht-projects-maven.html" target="_blank">CQ Project Set Up </a><br />
<br />
<b><u>Solution:</u></b> Include following line in your dependency management for your pom.xml (Depending upon project this could be at any location usually it is your Project parent pom)<br />
<br />
<br />
<div class="p1" style="text-align: left;">
<span style="color: blue;"><dependencyManagement></span><br />
<span style="color: blue;"><!-- All Your Third party dependency --></span><br />
<span style="color: blue;"><!-- AEM 6.0 --></span><br />
<span style="color: blue;"><br /></span><span style="color: blue;"> <!-- All AEM Dependencies for JSP compilation --><br /><br /> <dependency><br /> <groupId>com.adobe.aem</groupId><br /> <artifactId>aem-api</artifactId><br /> <version>6.0.0.1</version><br /> <scope>provided</scope><br /> </dependency><br /><br /> <!-- All AEM 6.1 Dependency added to end of file --></span><br />
<span style="color: blue;"><br /> <dependency><br /> <groupId>com.adobe.cq.social</groupId><br /> <artifactId>cq-socialcommunities-api</artifactId><br /> <version>1.7.197</version><br /> <scope>provided</scope><br /> </dependency></span><br />
<span style="color: blue;"><br /> <dependency><br /> <groupId>com.adobe.aem</groupId><br /> <artifactId>uber-jar</artifactId><br /> <version>6.1.0</version><br /> <scope>provided</scope><br /> <classifier>obfuscated-apis</classifier><br /> </dependency></span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"></dependencyManagement></span></div>
<div class="p1">
<span class="s1"><span class="s2"><br /></span></span></div>
<div class="p1">
<span class="s1"><span class="s2"><b><u>Note</u></b> that this version could change depending upon new releases of CQ, You can track them from <a href="http://repo.adobe.com/nexus/content/repositories/releases/com/adobe/aem/aem-api/" target="_blank">http://repo.adobe.com/nexus/content/repositories/releases/com/adobe/aem/aem-api/</a></span></span><br />
<span class="s1"><br /></span>
<span class="s1"><b>Some Trick:</b> Note that above will include all AEM-API dependencies, other way to check what minimum dependency is needed is to create a multi module project using AEM plugin for eclipse more example <a href="http://docs.adobe.com/content/docs/en/dev-tools/aem-eclipse.html" target="_blank">http://docs.adobe.com/content/docs/en/dev-tools/aem-eclipse.html</a> .</span><br />
<br />
<span class="s1">You can also upload <a href="https://drive.google.com/file/d/0B6solO-ErCt7a2FxcUsxaHExN0U/view?usp=sharing" target="_blank">uber-jar</a> with apis classifiers instead of obfuscate-apis classifier to your Nexus or dependency management system. </span><br />
<span class="s1"><br /></span>
<span class="s1">To upload this uber-jar to your nexus you can use something like,</span><br />
<span class="s1"><br /></span>
<span class="s1">mvn deploy:deploy-file -Durl=YOUR-REPO -Dfile=uber-jar-6.1.0-apis.jar -DartifactId=uber-jar -Dversion=6.1.0 -DgroupId=com.adobe.aem -Dclassifier=apis -Dpackaging=jar -DrepositoryId=YOUR-REPO-ID</span><br />
<span class="s1"><br /></span>
<span class="s1">Once you have uber-jar with apis classifier ready, You can use something like</span><br />
<span class="s1"><br /></span>
<span class="s1"><span style="color: blue;"> <dependency><br /> <groupId>com.adobe.aem</groupId><br /> <artifactId>uber-jar</artifactId><br /> <version>6.1.0</version><br /> <classifier>apis</classifier><br /> <scope>provided</scope><br /> </dependency></span></span><br />
<span class="s1"><br /></span>
<span class="s1">I see that minimum these are needed when you use this,</span><br />
<span class="s1"><br /></span>
<script src="https://gist.github.com/yupadhyay/3c937492f1376254410e.js"></script>
</div>
<div class="p1">
As always let me know if you want me to add more details in this posting.</div>
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com2tag:blogger.com,1999:blog-5778419059463879376.post-23703315865822173062014-06-25T15:57:00.003-07:002014-08-27T12:28:04.885-07:00How to add binary property for Node in CQ<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Motivation:</b> Recently I was trying to add some binary property to a node through file system (As part of code deployment). Had hard time figuring out how we can do that.<br />
<br />
<b>Use Case:</b> You need to add some Binary property to a node through file system. (One use case is adding SAML cert as property idp_cert under /etc/key/saml)<br />
<br />
<b>Solution:</b><br />
<br />
<b>Option 1:</b><br />
<br />
You can use following curl command to do that (Look at \< )<br />
<br />
<br />
<div class="p1">
<span style="color: blue;">curl -u UID:PWD -F property_name=<b>\<</b>File location -F property_name@TypeHint=Binary http://HOST:PORT/PATH_WHERE_YOU_WANT_TO_ADD_THIS_PROP</span></div>
<div class="p1">
<br /></div>
<div class="p1">
If you are trying to upload a file instead of property, You can use something like, (This is even true for if you want to install a bundle using repo path in that case repo path would be something like /apps/your_app/install if this is Adobe bundle then something like /libs/adobe_modules/install and if this is system bundle (Like Authentication bundles) then it would be something like /libs/system/install</div>
<div class="p1">
<br /></div>
<div class="p1">
<span style="color: blue;">curl -u UID:PWD -T File_Location HOST:PORT/PATH</span></div>
<div class="p1">
<br /></div>
<div class="p1">
<b>Option 2:</b> </div>
<div class="p1">
<br /></div>
<div class="p1">
You can use .content.xml to create property like this</div>
<div class="p1">
<br /></div>
<div class="p1">
<span style="color: blue;"><span class="s1"><?</span><span class="s2">xml</span><span class="s3"> </span>version<span class="s3">=</span><span class="s4">"1.0"</span><span class="s3"> </span>encoding<span class="s3">=</span><span class="s4">"UTF-8"</span><span class="s1">?></span></span></div>
<div class="p2">
<span style="color: blue;"><span class="s1"><</span><span class="s2">jcr:root</span><span class="s3"> </span><span class="s5">xmlns:sling</span><span class="s3">=</span>"http://sling.apache.org/jcr/sling/1.0"<span class="s3"> </span><span class="s5">xmlns:jcr</span><span class="s3">=</span>"http://www.jcp.org/jcr/1.0"<span class="s3"> </span><span class="s5">xmlns:rep</span><span class="s3">=</span>"internal"</span></div>
<div class="p2">
<span style="color: blue;"><span class="s3"> </span><span class="s3"><span class="s3"> </span><span class="s5">your_property-name</span>=</span>"{Binary}"</span></div>
<div class="p1">
</div>
<div class="p1">
<span style="color: blue;"><span class="s3"> </span>jcr:primaryType<span class="s3">=</span><span class="s4">"sling:Folder"</span><span class="s1">/></span></span></div>
<div class="p1">
<span class="s1"><br /></span></div>
<div class="p1">
<span class="s1">And then create a file called </span><span class="s3"> </span><span class="s5">your_property-name.binary at same level and dump your binary content there. When you use maven-content-plugin to build package now, vlt knows how to transform this to a binary property.</span></div>
<div class="p1">
<span class="s5"><br /></span></div>
<div class="p1">
<span class="s5"><span style="color: blue;">----- /somepath</span></span></div>
<div class="p1">
<span class="s5"><span style="color: blue;">-------- .content.xml</span></span></div>
<div class="p1">
<span class="s5"><span style="color: blue;">-------- your_property_name.binary</span></span></div>
<div class="p1">
<span class="s5"><br /></span></div>
<div class="p1">
<span class="s5">Note that there are various way to create actual binary content in CQ using curl and some of them you can check here </span></div>
<div class="p1">
<span class="s5"><br /></span></div>
<div class="p1">
<span class="s5"><a href="http://sling.apache.org/documentation/bundles/manipulating-content-the-slingpostservlet-servlets-post.html" target="_blank">http://sling.apache.org/documentation/bundles/manipulating-content-the-slingpostservlet-servlets-post.html</a></span></div>
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com20tag:blogger.com,1999:blog-5778419059463879376.post-51874365455281435182014-05-14T16:42:00.001-07:002014-06-10T12:38:11.483-07:00How to find component load time on a page in CQ<div dir="ltr" style="text-align: left;" trbidi="on">
<b><u>Use Case:</u></b> Your page is loading slow and you want to know which component in a page is slow in render<br />
<br />
<b><u>Solution:</u></b> You can use CQ timing info to get that data. timing load uses resource dumper <a href="https://sling.apache.org/apidocs/sling5/org/apache/sling/api/request/RequestProgressTracker.html" target="_blank">https://sling.apache.org/apidocs/sling5/org/apache/sling/api/request/RequestProgressTracker.html</a> to track load time of each jsp within page.<br />
<br />
To enable debugging<br />
<br />
<b><u>version <= CQ5.6.1</u></b><br />
<br />
1) Go to /libs/foundation/components/timing/timing.jsp through CRXDE light and comment following like of code<br />
<br />
//uncomment the following to get more timing details in the page<br />
out.println("\nRaw RequestProgressTracker data:");<br />
StringBuilder mb = new StringBuilder();<br />
Iterator<String> it = t.getMessages();<br />
while(it.hasNext()) {<br />
mb.append(it.next());<br />
}<br />
out.print(mb.toString());<br />
out.println("\nChartData dump:");<br />
for(ChartBar d : chartData) {<br />
out.print(d.start);<br />
out.print(' ');<br />
out.print(d.fullname);<br />
out.print(" (");<br />
out.print(d.elapsed);<br />
out.println("ms)");<br />
}<br />
<br />
2) Make sure that timing.jsp is included in your global template using<br />
<br />
<cq:include path="timing" resourceType="foundation/components/timing"/><br />
<br />
3) Load your page and do view source<br />
<br />
4) Scroll down to bottom of page where you will see google chart URL<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiamxmZqsFVtO_KHFQjMx3nFQcJS5YbCGUysm1liscbbm5nR68Vc30YrjI4s1tk0mpPnJkrFPMACtXAmCC-tOcnFjzCqahYSTrz1sQjQqRoV_MNMBSylMnQM-lSn_fq7QM21VPa9mIzul8/s1600/View_Source_Timing.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiamxmZqsFVtO_KHFQjMx3nFQcJS5YbCGUysm1liscbbm5nR68Vc30YrjI4s1tk0mpPnJkrFPMACtXAmCC-tOcnFjzCqahYSTrz1sQjQqRoV_MNMBSylMnQM-lSn_fq7QM21VPa9mIzul8/s1600/View_Source_Timing.png" height="61" width="320" /></a></div>
<br />
<br />
5) Copy that URL and paste it in browser to get timing info<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzkohxrJx7Y-j7lM33IwQYDtl-uqjgr0QXTeVqr90qHIgSjruajKHJ5FAqfisr31KK4sL7XhHK1_sPFA52YTkLaeznMuHvrA6JgUTFA9Cj7jcd7Klt0dqBXlarRh10ctZWoDSVg38IhQ0/s1600/JSP_Page_Load_Time.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzkohxrJx7Y-j7lM33IwQYDtl-uqjgr0QXTeVqr90qHIgSjruajKHJ5FAqfisr31KK4sL7XhHK1_sPFA52YTkLaeznMuHvrA6JgUTFA9Cj7jcd7Klt0dqBXlarRh10ctZWoDSVg38IhQ0/s1600/JSP_Page_Load_Time.png" height="224" width="320" /></a></div>
<br />
<b><u><br /></u></b>
<b><u>CQ > 6</u></b><br />
<b><u><br /></u></b>
CQ 6 has this feature OOTB<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmElTAzbzOWYW-gEkP7IQzKF8rfYDrg0dfyUTFDk9VdLd4x2MxHmsEKIthDTVplzDIsQ_aEgx35SJmQFM7o9sA47XSBx5IvmJfy9YiWtJ_Z3Rpu55Q_TJZ_s1lWvaYYgvYtY6LxH4ALGQ/s1600/CQ6_Page_Load_Analysis.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmElTAzbzOWYW-gEkP7IQzKF8rfYDrg0dfyUTFDk9VdLd4x2MxHmsEKIthDTVplzDIsQ_aEgx35SJmQFM7o9sA47XSBx5IvmJfy9YiWtJ_Z3Rpu55Q_TJZ_s1lWvaYYgvYtY6LxH4ALGQ/s1600/CQ6_Page_Load_Analysis.png" height="231" width="320" /></a></div>
<br />
<b><u><br /></u></b>
<b><u>Notes:</u></b> Please also read <a href="http://dev.day.com/docs/en/cq/current/deploying/monitoring_and_maintaining.html" target="_blank">http://dev.day.com/docs/en/cq/current/deploying/monitoring_and_maintaining.html</a> to see how you can analyze request log to find page load time on server side. This is also very useful to find any thread contention issues wither using thread dump or session dump from felix console.<br />
<br />
On client side there are different products you can use (I don't have preference) (<a href="http://www.appdynamics.com/blog/devops/load-testing-tools-explained-the-client-side/" target="_blank">AppDynamic</a>, <a href="http://newrelic.com/" target="_blank">New Relic</a>, <a href="https://developers.google.com/speed/pagespeed/module" target="_blank">Google Page Speed</a>, <a href="http://www.google.com/analytics/" target="_blank">Google Analytics</a> etc) to find client side load time.</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com4tag:blogger.com,1999:blog-5778419059463879376.post-80206828530647970682014-04-21T13:54:00.000-07:002014-11-05T09:58:39.491-08:00How to use sling thread pool in CQ/AEM<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Use Case:</b> You are designing an application where you might need to delegate Job to a separate thread and you want to control this using thread pool so that your application it self does not run out of threads.<br />
<br />
<b>Prerequisite:</b> Knowledge of Java Threads and basic Knowledge of thread pool. Note that there are Java Level thread pool as well that you can use. Check <a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html" target="_blank">http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html</a> for that.<br />
<br />
<b>Reference:</b> <a href="https://sling.apache.org/documentation/bundles/apache-sling-commons-thread-pool.html" target="_blank">https://sling.apache.org/documentation/bundles/apache-sling-commons-thread-pool.html</a><br />
<br />
<b><u>Implementation Example:</u></b><br />
<br />
<b>Step 1:</b> Create your Thread class<br />
<br />
public YourThreadClass implements Runnable {<br />
<br />
<br />
<div class="p1">
<span class="s1"> </span>public<span class="s1"> </span>void<span class="s1"> run() {</span></div>
<div class="p1">
<span class="s1"> //Your custom logic</span></div>
<div class="p1">
<span class="s1">}</span></div>
}<br />
<br />
<b>Step 2:</b> Main class to use sling Thread pool<br />
<br />
<script src="https://gist.github.com/yupadhyay/a184b3d9bbd6abffc30b.js"></script>
<br />
Use CQ dependency finder to find what dependency you need for above code in your pom.xml</div>Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com49tag:blogger.com,1999:blog-5778419059463879376.post-31644969614076316772014-01-22T11:53:00.003-08:002014-11-05T10:01:04.988-08:00How to include CQ package from other projects as dependency in your project<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Use Case:</b> We often come across situation where we want to include package or jar files from other CQ project across organization to your project.<br />
<br />
<b>Set Up:</b> This assumes that you already have your project set up using Maven, Nexus. You need Nexus or any other repository management system to store artifact of jar or CQ package zip artifact you need to use in your project.<br />
<br />
<b>Assumption:</b> You are using "content-package-<span class="s1">maven</span>-<span class="s1">plugin" to create CQ package. More information about this artifact can be found here </span><br />
<span class="s1"><a href="http://dev.day.com/docs/en/cq/current/core/how_to/how_to_use_the_vlttool/vlt-mavenplugin.html" target="_blank">http://dev.day.com/docs/en/cq/current/core/how_to/how_to_use_the_vlttool/vlt-mavenplugin.html</a></span><br />
<br />
<b>Solution:</b><br />
<br />
For jar file it is simply adding it to your embed statement and for zip file you could use subPackages configuration. Once you will run maven install with this configuration, Other project package will also get installed with your package. Same works for uninstall of package as well. Geometrixx all package uses similar approach.<br />
<br />
your final pom will look like this,<br />
<br />
<script src="https://gist.github.com/yupadhyay/c63992c3d2e238cb4a3a.js"></script>
<br />
<div class="p4">
</div>
<div class="p4">
<b>NOTE</b>: When you are using other CQ projects as dependency in to your project, make sure that other project is not overriding configurations in your project. You might have to adjust other project package filter accordingly. </div>
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com5tag:blogger.com,1999:blog-5778419059463879376.post-55408774332517967842013-12-09T11:00:00.000-08:002013-12-09T11:24:32.763-08:00How to fix com.day.crx.persistence.tar.ClusterTarSet Could not open java.io.IOException: Bad file descriptor Issue in CQ<div dir="ltr" style="text-align: left;" trbidi="on">
<b><u>Issue:</u></b> Server does not start and you see following error in logs<br />
<br />
<div class="p1">
<br /></div>
<div class="p1">
*WARN* [FelixStartLevel] com.day.crx.persistence.tar.ClusterTarSet Could not open java.io.IOException: Bad file descriptor</div>
<div class="p1">
at java.io.RandomAccessFile.writeBytes(Native Method)</div>
<div class="p1">
at java.io.RandomAccessFile.write(RandomAccessFile.java:486)</div>
<div class="p1">
at com.day.crx.persistence.tar.file.TarFile.write(TarFile.java:742)</div>
<div class="p1">
at com.day.crx.persistence.tar.file.TarFile.writeData(TarFile.java:635)</div>
<div class="p1">
at com.day.crx.persistence.tar.file.TarFile.appendMetaData(TarFile.java:709)</div>
<div class="p1">
at com.day.crx.persistence.tar.file.TarFile.append(TarFile.java:591)</div>
<div class="p1">
at com.day.crx.persistence.tar.TarSet.switchDataFile(TarSet.java:445)</div>
<div class="p1">
at com.day.crx.persistence.tar.TarSet.open(TarSet.java:227)</div>
<div class="p1">
at com.day.crx.persistence.tar.ClusterTarSet.reopenCopy(ClusterTarSet.java:1455)</div>
<div class="p1">
at com.day.crx.persistence.tar.ClusterTarSet.open(ClusterTarSet.java:860)</div>
<div class="p1">
at com.day.crx.persistence.tar.TarPersistenceManager.openTarSet(TarPersistenceManager.java:980)</div>
<div class="p1">
at com.day.crx.persistence.tar.TarPersistenceManager.init(TarPersistenceManager.java:500)</div>
<div class="p1">
at com.day.crx.core.CRXRepositoryImpl.createVersionManager(CRXRepositoryImpl.java:869)</div>
<div class="p1">
at org.apache.jackrabbit.core.RepositoryImpl.<init>(RepositoryImpl.java:311)</div>
<div class="p1">
at com.day.crx.core.CRXRepositoryImpl.<init>(CRXRepositoryImpl.java:307)</div>
<div class="p1">
at com.day.crx.core.CRXRepositoryImpl.create(CRXRepositoryImpl.java:262)</div>
<div class="p1">
at com.day.crx.core.CRXRepositoryImpl.create(CRXRepositoryImpl.java:245)</div>
<div class="p1">
at com.day.crx.sling.server.impl.jmx.ManagedRepository.activate(ManagedRepository.java:170)</div>
<div class="p1">
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)</div>
<div class="p1">
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)</div>
<div class="p1">
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)</div>
<div class="p1">
at java.lang.reflect.Method.invoke(Method.java:601)</div>
<div class="p1">
at org.apache.felix.scr.impl.helper.BaseMethod.invokeMethod(BaseMethod.java:236)</div>
<div class="p1">
at org.apache.felix.scr.impl.helper.BaseMethod.access$500(BaseMethod.java:37)</div>
<div class="p1">
at org.apache.felix.scr.impl.helper.BaseMethod$Resolved.invoke(BaseMethod.java:613)</div>
<div class="p1">
at org.apache.felix.scr.impl.helper.BaseMethod.invoke(BaseMethod.java:496)</div>
<br />
<div class="p1">
at org.apache.felix.scr.impl.helper.ActivateMethod.invoke(ActivateMethod.java:149)</div>
<div class="p1">
<br /></div>
<div class="p1">
<b><u>Solution: </u></b></div>
<div class="p1">
<br /></div>
<div class="p1">
1) Find a line above this error, it would be something like</div>
<div class="p1">
<br /></div>
<div class="p1">
09.12.2013 13:42:32.030 *INFO* [FelixStartLevel] com.day.crx.persistence.tar.TarSet scanning index <some path>/crx-quickstart/repository/<either version or workspace>/data_<some number>.tar </div>
<div class="p1">
<br /></div>
<div class="p1">
2) Based on path go to that location.</div>
<div class="p1">
3) STOP YOUR INSTANCE. remove all index files using <span style="color: blue;"><i>rm -rf <Path from above>/index*tar</i></span></div>
<div class="p1">
4) change permission of data tar file using <span style="color: blue;"><i>chmod 644 <path from above>/data*tar</i></span></div>
<div class="p1">
5) Start instance</div>
<div class="p1">
6) Some cases data tar files can not be recovered. Please check my other post to fix non recovery data tar files.</div>
<div class="p1">
<br /></div>
<div class="p1">
<span style="color: red;"><b>Caution: If there are a lot of data tar files, Index creation may take some time. Please create daycare ticket to find root cause of this issue.</b></span></div>
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com0tag:blogger.com,1999:blog-5778419059463879376.post-71594232738708022512013-07-31T10:47:00.000-07:002014-07-28T10:05:52.367-07:00How to host Adobe Dynamic Tag Management System files in CQ dispatcher<div dir="ltr" style="text-align: left;" trbidi="on">
<b><u>Use Case:</u></b> You often have situation where for marketing and analytics purpose you have to reply on dev team to push tracking code or tag management code or inclusion of any third party client side library. <a href="https://dtm.adobe.com/" target="_blank">Satellite Search and Discovery</a> provide great way to abstract client side tracking or tagging changes for marketing and analytics with development.<br />
Documentation on Tag Management can be found <a href="http://microsite.omniture.com/t2/help/en_US/dtm/dtm_get_started.pdf" target="_blank">here</a><br />
<br />
<b><u>Challenges: </u></b><br />
<br />
1) Update to CQ could happen out side dev cycle. For this make sure that satellite changes are completely tested before using it in production.<br />
2) Since Satellite is similar to SAS service, changes in satellite could also cause some module not to work as expected. For that you can keep track of changes in satellite side and test that module.<br />
3) Some time satellite load is slow if it is loaded from there hosted service. For this you can host satellite code on dispatcher and use some script to update it every time there is any change.<br />
<br />
<b>Include satellite script to CQ:</b><br />
<br />
You can simply use,<br />
<br />
<div class="p1">
<span class="s1"><</span><span class="s2">script</span><span class="s3"> </span><span class="s4">type</span><span class="s3">=</span>"text/javascript"<span class="s3"> </span><span class="s4">src</span><span class="s3">=</span>"SOME-PATH.js"<span class="s3"> </span><span class="s1">></</span><span class="s2">script</span><span class="s1">></span></div>
<div class="p1">
<span class="s1">you can also use run mode specific configuration to include dev or prod specific script to your side.</span></div>
<div class="p1">
<span class="s1">
</span></div>
<div class="p1">
Set<String> runModes = sling.getService(SlingSettingsService.<span class="s1">class</span>).getRunModes();</div>
<div class="p1">
if(!runModes.contains(<span class="s1">"author"</span>)) { </div>
<div class="p1">
if(runModes.contains(<span class="s1">"prod"</span>){</div>
<div class="p1">
//Include prod satellite code</div>
<div class="p1">
}else{</div>
<div class="p1">
//Include dev satellite code</div>
<div class="p1">
}</div>
<div class="p1">
}</div>
<div class="p1">
<br /></div>
<div class="p1">
<b>Host satellite Script on Dispatcher:</b></div>
<div class="p1">
<br /></div>
<div class="p1">
For performance you can host satellite on dispatcher itself and then include it in your file. For this satellite provide a feature for deploy Hook. Deploy hook URL is called every time there is a change in any configuration or any rules are published. </div>
<div class="p1">
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwC_vb9Je_GqtVYyen94MpscM7-4L4CX53NZHdQy6DFbZdN8jsM0kV88OFybDUO1Cj457xTCF5h9Uxz2gjU2YyDNoHhZWQQpWobfxfhcdYqUUo0Xo9liP_iTBkq9Ayx1boHeBh3hkrvZ8/s1600/Satellite+Search+Discovery+With+CQ.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwC_vb9Je_GqtVYyen94MpscM7-4L4CX53NZHdQy6DFbZdN8jsM0kV88OFybDUO1Cj457xTCF5h9Uxz2gjU2YyDNoHhZWQQpWobfxfhcdYqUUo0Xo9liP_iTBkq9Ayx1boHeBh3hkrvZ8/s400/Satellite+Search+Discovery+With+CQ.png" height="261" width="400" /></a></div>
<br />
<br /></div>
<div class="p1">
If you want to host satellite files on dispatcher then you can give this deploy hook URL as your production server URL path that you want to call every time there is any change. For example I want call a servlet or any script on change and update change in dispatcher and all other publish and author instance.</div>
<div class="p1">
<br /></div>
<div class="p1">
Here I am using python script to make this update, Process is like this,</div>
<div class="p1">
</div>
<ul style="text-align: left;">
<li>Changes made in satellite</li>
<li>Satellite call a dispatcher URL</li>
<li>Dispatcher URL invoke python script (You need rewrite rule to do that)</li>
<li>Python script checks if this is staging or production server</li>
<li>Based on that it get corresponding satellite files which is in zip fomat</li>
<li>Script unzip file, remove existing files from dispatcher if present and put it in dispatcher in certain location</li>
<li>Then it calls other dispatchers to update files as well</li>
<li>Then it issue upload request to upload changed file to author</li>
<li>After that it issue tree activation request to update these files on all publish. (This step is required in case some one clear dispatcher cache).</li>
<li>In order to avoid infinite loop within all dispatchers, one dispatcher call other dispatcher with a URL param indicating not to call other dispatcher.</li>
<li>for UID:PWD you can use non admin users that only have access to satellite files, make sure that they have activation rights as well.</li>
</ul>
<br />
<div class="p1">
You can use </div>
<div class="p1">
<br /></div>
<div class="p1">
Note: I am using old version of python, You can reduce code with latest version.</div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
#!/<span class="s1">usr</span>/bin/<span class="s1">python</span></div>
<div class="p1">
import urllib2</div>
<div class="p1">
import <span class="s1">shutil</span></div>
<div class="p1">
import <span class="s1">urlparse</span></div>
<div class="p1">
import <span class="s1">os</span></div>
<div class="p1">
import <span class="s1">sys</span></div>
<div class="p1">
import <span class="s1">zipfile</span></div>
<div class="p1">
import <span class="s1">cgitb</span>; cgitb.enable()</div>
<div class="p1">
import <span class="s1">cgi</span></div>
<div class="p1">
import socket</div>
<div class="p1">
import <span class="s1">urllib</span></div>
<div class="p1">
#import <span class="s1">pwd</span></div>
<div class="p1">
#import <span class="s1">grp</span></div>
<div class="p1">
#Global <span class="s1">Var</span></div>
<div class="p1">
#Read URL from path</div>
<div class="p1">
#Staging IP List contain list of IP for Stage</div>
<div class="p1">
staging_IP_list = ["X.X.X.X","X.X.X.X"]</div>
<div class="p1">
#Production IP list</div>
<div class="p1">
production_IP_list = ["Y.Y.Y.Y","Y.Y.Y.Y","Y.Y.Y.Y","Y.Y.Y.Y"]</div>
<div class="p1">
#This is required to avoid circular loop</div>
<div class="p1">
form = cgi.FieldStorage()</div>
<div class="p1">
checked = form.getvalue("checked")</div>
<div class="p1">
<span class="s1">addr</span> = socket.gethostbyname(socket.gethostname())</div>
<div class="p1">
#This folder path is required to avoid permission issue.</div>
<div class="p1">
rootFolder = "../some/folder/in/dispatcher"</div>
<div class="p1">
#Need to create rewrite mapping for this to work.</div>
<div class="p1">
pingUrl = "/some/path/for/dispatcher?checked=true"</div>
<div class="p1">
staging_satellite_url="THIS IS THE URL WHERE DEV SATELLITE FILE IS HOSTED"</div>
<div class="p1">
production_satellite_url="THIS IS THE URL WHERE PROD SATELLITE FILE IS HOSTED"</div>
<div class="p1">
<span class="s1">url</span>=staging_satellite_url</div>
<div class="p1">
author_content_folder="FOLDER NAME WHERE YOU WANT THIS FILE TO GO"</div>
<div class="p1">
author_content_subfolder="SUBFOLDER NAME GIVEN BY SATELLITE /"</div>
<div class="p1">
satellite_js_file_name="SATELLITE FILE NAME GIVEN BY SATELLITE"</div>
<div class="p1">
staging_author_server="YOUR-STAGING-AUTHOR-SERVER"</div>
<div class="p1">
production_author_server="YOUR-PRODUCTION-AUHTOR-SERVER"</div>
<div class="p1">
curl_ping_url=staging_author_server</div>
<div class="p1">
script_file_list=[]</div>
<div class="p1">
#Destination Path</div>
<div class="p1">
print "Content-type: text/<span class="s1">html</span>; <span class="s1">charset</span>=<span class="s1">iso</span>-8859-1\n\n"</div>
<div class="p1">
print '''<HTML>'''</div>
<div class="p1">
print '''<TITLE>Satellite Ping Check</TITLE><body>'''</div>
<div class="p1">
#print '''<br><span class="s1">url</span> I got host as''',<span class="s1">addr</span></div>
<div class="p2">
<br /></div>
<div class="p1">
#This method override <span class="s1">url</span> open to make just head request</div>
<div class="p1">
class HeadRequest(urllib2.Request):</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="s1">def</span> get_method(self):</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>return "HEAD"</div>
<div class="p2">
<br /></div>
<div class="p1">
#Method to ping URL to another server</div>
<div class="p1">
<span class="s1">def</span> pingURL(customURL):</div>
<div class="p1">
<span class="Apple-tab-span"> </span>try:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>response = urllib2.<span class="s1">urlopen</span>(HeadRequest(customURL))</div>
<div class="p1">
<span class="Apple-tab-span"> </span>except:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>print '''<br>We failed to reach a server.'''</div>
<div class="p2">
<br /></div>
<div class="p1">
#Method that will ping other server based on IP address</div>
<div class="p1">
<span class="s1">def</span> pingOtherServer():</div>
<div class="p1">
<span class="Apple-tab-span"> </span>for eachIp in staging_IP_list:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>if eachIp==<span class="s1">addr</span>:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>for eachIp2 in staging_IP_list:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>if eachIp2!=<span class="s1">addr</span>:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="s1">resp</span> = pingURL("http://"+eachIp2+pingUrl)</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>break</div>
<div class="p1">
<span class="Apple-tab-span"> </span>for eachIp in production_IP_list:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>if eachIp==<span class="s1">addr</span>:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>for eachIp2 in production_IP_list:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>if eachIp2!=<span class="s1">addr</span>:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="s1">resp</span> = pingURL("http://"+eachIp2+pingUrl)</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>break</div>
<div class="p2">
<br /></div>
<div class="p2">
<br /></div>
<div class="p1">
#This is required to keep those files to author</div>
<div class="p1">
<span class="s1">def</span> pingauthorServer():</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="s1">filepath</span> = rootFolder+"/"+author_content_subfolder+satellite_js_file_name</div>
<div class="p1">
<span class="Apple-tab-span"> </span>#Curl command to upload satellite file</div>
<div class="p1">
<span class="Apple-tab-span"> </span>os.system('curl -u UID:PWD -F@TypeHint="nt:file" -<span class="s1">Ftype</span>="file" --upload-file '+<span class="s1">filepath</span>+' '+curl_ping_url+author_content_folder+author_content_subfolder)</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="s1">filepath</span>=rootFolder+"/"+"selector.js"</div>
<div class="p1">
<span class="Apple-tab-span"> </span>#Curl command to upload selectors.js file</div>
<div class="p1">
<span class="Apple-tab-span"> </span>os.system('curl -u UID:PWD -F@TypeHint="nt:file" -<span class="s1">Ftype</span>="file" --upload-file '+<span class="s1">filepath</span>+' '+curl_ping_url+author_content_folder)</div>
<div class="p1">
<span class="Apple-tab-span"> </span>for script_file in script_file_list:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="s1">filepath</span>=rootFolder+"/"+author_content_subfolder+"scripts/"+script_file</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>os.system('curl -u UID:PWD -F@TypeHint="nt:file" -<span class="s1">Ftype</span>="file" --upload-file '+<span class="s1">filepath</span>+' '+curl_ping_url+author_content_folder+author_content_subfolder+"scripts/")</div>
<div class="p1">
<span class="Apple-tab-span"> </span>#Curl command to activate files to publish instance</div>
<div class="p1">
<span class="Apple-tab-span"> </span>os.system('curl -u UID:PWD -<span class="s1">Fcmd</span>=activate -<span class="s1">Fignoredeactivated</span>=true -<span class="s1">Fonlymodified</span>=false -<span class="s1">Fpath</span>='+author_content_folder+' '+curl_ping_url+'/etc/replication/treeactivation.html')</div>
<div class="p2">
<br /></div>
<div class="p1">
#Method to delete existing folder before extracting new one</div>
<div class="p1">
<span class="s1">def</span> deleteFileOrFolder(directory):</div>
<div class="p1">
if os.path.exists(directory):</div>
<div class="p1">
try:</div>
<div class="p1">
if os.path.isdir(directory):</div>
<div class="p1">
print '''<br>removing folder<b>''',directory</div>
<div class="p1">
shutil.rmtree(directory)</div>
<div class="p1">
print '''<br>Creating''',directory</div>
<div class="p1">
os.makedirs(directory)</div>
<div class="p1">
else:</div>
<div class="p1">
print '''<br>removing file<b>''',directory</div>
<div class="p1">
os.remove(directory)</div>
<div class="p1">
except:</div>
<div class="p1">
print '''<br><span class="s1">Ecxeption</span>''',<span class="s1">str</span>(sys.exc_info())</div>
<div class="p1">
else:</div>
<div class="p1">
print '''<br>not found''',directory</div>
<div class="p1">
print '''<br>Creating''',directory</div>
<div class="p1">
os.makedirs(directory)</div>
<div class="p2">
<br /></div>
<div class="p1">
#Method to set satellite <span class="s1">url</span> based on IP address. If this is production server then set URL as production</div>
<div class="p1">
<span class="s1">def</span> <span class="s1">seturl</span>():</div>
<div class="p1">
<span class="Apple-tab-span"> </span>for eachIp in production_IP_list:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>if eachIp==<span class="s1">addr</span>:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>global <span class="s1">url</span></div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="s1">url</span>=production_satellite_url</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>global satellite_js_file_name</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>satellite_js_file_name="YOUR-SATELLITE-FILE-NAME.<span class="s1">js</span>"</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>global curl_ping_url</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>curl_ping_url=production_author_server</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>break</div>
<div class="p2">
<br /></div>
<div class="p2">
<br /></div>
<div class="p1">
<span class="s1">def</span> extract():</div>
<div class="p1">
<span class="Apple-tab-span"> </span>zip_file = zipfile.ZipFile(fileName, 'r')</div>
<div class="p1">
<span class="Apple-tab-span"> </span>#print '''file name is ''',fileName</div>
<div class="p1">
<span class="Apple-tab-span"> </span>for files in zip_file.namelist():</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>print '''<br>files in <span class="s1">zip</span>''',files</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>myfile_path=rootFolder+"/"+files</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>#print '''<br> <span class="s1">Yogesh</span> ''',myfile_path</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>if myfile_path.endswith("/"):</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>#print '''<br>I am in if and myfile_path is ''',myfile_path</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>if not os.path.exists(myfile_path):</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>os.makedirs(myfile_path)</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>else:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>if files.find("/scripts/") != -1:</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>script_file_list.append(files.split('/')[-1])</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>#print '''<b> found script file with name <br>''',rootFolder+"/"+author_content_subfolder+"scripts/"+files.split('/')[-1]</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>#print '''<br>I am here and myfile_path is ''',myfile_path</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>data = zip_file.read(files)</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="s1">myfile</span> = open(myfile_path, "w+")</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>myfile.write(data)</div>
<div class="p1">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>myfile.close()</div>
<div class="p1">
<span class="Apple-tab-span"> </span>zip_file.close()</div>
<div class="p2">
<br /></div>
<div class="p1">
#Setting URL to production if this is production server. By default it is always staging server</div>
<div class="p1">
<span class="s1">seturl</span>()</div>
<div class="p1">
#print '''<br><span class="s1">url</span> I got is''',<span class="s1">url</span></div>
<div class="p1">
fileName = url.split('/')[-1].split('#')[0].split('?')[0]</div>
<div class="p1">
print '''<br>filename I got is''',fileName</div>
<div class="p1">
#Delete all file and folder before creating them</div>
<div class="p1">
#deleteFileOrFolder(rootFolder+"/"+fileName)</div>
<div class="p1">
deleteFileOrFolder(rootFolder)</div>
<div class="p1">
r = urllib2.<span class="s1">urlopen</span>(urllib2.Request(<span class="s1">url</span>))</div>
<div class="p1">
try:</div>
<div class="p1">
<span class="Apple-tab-span"> </span>fileName = rootFolder+"/"+fileName</div>
<div class="p1">
<span class="Apple-tab-span"> </span>f=open(fileName, '<span class="s1">wb</span>')</div>
<div class="p1">
<span class="Apple-tab-span"> </span>urllib.urlretrieve(<span class="s1">url</span>,fileName)</div>
<div class="p1">
finally:</div>
<div class="p1">
r.close()</div>
<div class="p1">
#<span class="s1">zfile</span> = zipfile.ZipFile(fileName)</div>
<div class="p1">
extract()</div>
<div class="p1">
#zfile.extractall(rootFolder)</div>
<div class="p1">
#os.system('jar -<span class="s1">xvf</span> '+fileName)</div>
<div class="p1">
#Do it only from one server</div>
<div class="p1">
if checked is None:</div>
<div class="p1">
<span class="Apple-tab-span"> </span>pingOtherServer()</div>
<div class="p1">
<span class="Apple-tab-span"> </span>pingauthorServer()</div>
<div class="p2">
<br /></div>
<div class="p1">
print '''</body>'''</div>
<div class="p1">
</div>
<div class="p1">
print '''</HTML>'''</div>
<div class="p1">
<br /></div>
<div class="p1">
Happy tagging and tracking. Let me know if you have any question.<br />
<br />
<span style="color: red;"><b>AEM 6</b> provide this feature OOTB for that go to http://HOST:PORT/miscadmin#/etc/cloudservices/dynamictagmanagement and enter your DTM info</span></div>
<div class="p1">
<br /></div>
<div class="p1">
<b><u>Note:</u></b> <span style="color: red;">Please note that there could be other tools that are capable of doing similar things. You can use similar approach there as well. This post has no mean to say that you should use satellite search and discovery for similar use case.</span></div>
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com1tag:blogger.com,1999:blog-5778419059463879376.post-43659423022034784282013-07-23T11:31:00.000-07:002014-10-29T14:18:15.110-07:00How to Create Custom Adapters in Adobe CQ / AEM <div dir="ltr" style="text-align: left;" trbidi="on">
<b><u>Prerequisite:</u></b> <a href="http://sling.apache.org/documentation/the-sling-engine/adapters.html" target="_blank">http://sling.apache.org/documentation/the-sling-engine/adapters.html</a><br />
<br />
<b><u>Use Case:</u></b> You often have a case where you want to adaptTo from existing object to custom Object or Provide adapter functionality for custom object to existing object.<br />
<br />
<b><u>Solution:</u></b> There are mainly two ways you can use adaptTo<br />
<br />
<b><u>Case 1:</u></b> You want existing object to be adaptable to custom object. For example you have a specific kind of node and you want Node or Resource to be adaptable to this object.<br />
<br />
CustomObject myCustomObject = resource.adaptTo(CustomObject.class)<br />
Or<br />
CustomObject myCustomObject = node.adaptTo(CustomObject.class)<br />
Or<br />
CustomObject myCustomObject = <ANY Adaptable OBJECT>.adaptTo(CustomObject.class)<br />
<br />
<b><u>Case 2:</u></b> You want custom object to be adaptable to existing object. For example you have specific kind of resource and you want this to be adaptable to existing resource.<br />
<br />
Node node = CustomObject.adaptTo(Node.class)<br />
Or<br />
Resource resource = CustomObject.adaptTo(Resource.class)<br />
Or<br />
<Any OOTB Adaptable> myObject = MycustomObject.adaptTo(<Any OOTB Adaptable>.class)<br />
<br />
<b><u>Case 1: Example</u></b><br />
<script src="https://gist.github.com/yupadhyay/7ff310bce4e6e731d6a8.js"></script>
<br />
<div class="p1">
<br /></div>
<div class="p1">
Here is how your CustomAdapter will look like</div>
<div class="p1">
<script src="https://gist.github.com/yupadhyay/21adc83aab342498deed.js"></script>
</div>
<div class="p1">
<br /></div>
<div class="p1">
<span style="color: blue;"><br /></span></div>
<div class="p1">
<b><u>Case 2: Example</u></b></div>
<div class="p1">
<script src="https://gist.github.com/yupadhyay/66a75634148454328a13.js"></script>
</div>
<div class="p1">
for this you can use slingAdaptable class <a href="https://dev.day.com/docs/en/cq/5-6/javadoc/org/apache/sling/api/adapter/SlingAdaptable.html" target="_blank">https://dev.day.com/docs/en/cq/5-6/javadoc/org/apache/sling/api/adapter/SlingAdaptable.html</a></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
One example (You can find more example here) <a href="http://svn.apache.org/repos/asf/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java" target="_blank">http://svn.apache.org/repos/asf/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java</a></div>
<div class="p1">
<br /></div>
<div class="p1">
In pom.xml you need following include. You can always find dependencies from HOST:PORT/system/console/depfinder</div>
<div class="p1">
<br /></div>
<div class="p1">
<span class="s1"><</span>dependency<span class="s1">></span></div>
<div class="p2">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span> <span class="s1"><</span><span class="s2">groupId</span><span class="s1">></span>org.apache.sling<span class="s1"></</span><span class="s2">groupId</span><span class="s1">></span></div>
<div class="p2">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span> <span class="s1"><</span><span class="s2">artifactId</span><span class="s1">></span>org.apache.sling.api<span class="s1"></</span><span class="s2">artifactId</span><span class="s1">></span></div>
<div class="p1">
<span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span> </span><span class="s1"><</span>version<span class="s1">></span><span class="s3">2.2.4</span><span class="s1"></</span>version<span class="s1">></span></div>
<div class="p2">
<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span> <span class="s1"><</span><span class="s2">scope</span><span class="s1">></span>provided<span class="s1"></</span><span class="s2">scope</span><span class="s1">></span></div>
<div class="p1">
</div>
<div class="p1">
<span class="s1"></</span>dependency<span class="s1">></span></div>
<div class="p1">
<br /></div>
<div class="p1">
<dependency></div>
<div class="p1">
<groupId>org.apache.sling</groupId></div>
<div class="p1">
<artifactId>org.apache.sling.adapter</artifactId></div>
<div class="p1">
<version>2.0.10</version></div>
<div class="p1">
<scope>provided</scope></div>
<div class="p1">
</dependency></div>
<div class="p1">
<br /></div>
<div class="p1">
Let me know if you have any question.</div>
</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com0tag:blogger.com,1999:blog-5778419059463879376.post-54847705039865108702013-06-22T12:59:00.000-07:002013-06-22T13:02:49.558-07:00How to implement robots.txt / sitemap.xml / crossdomain.xml in Adobe CQ / AEM<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Use Case: </b><br />
<br />
<ul style="text-align: left;">
<li>Some time you want to implement robots.txt or any web related configuration in CQ.</li>
<li>Some time you need to have different configuration of robots for different environment </li>
</ul>
<br />
<b>Solution: </b><br />
<br />
You can directly created web related configuration in CQ. For that do following,<br />
<br />
1) Go to CRXDE or CRXDE light, Or you can directly put them in your CVS under jcr_root folder. You can create different version of robots.txt based environment and domain name.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA-xGoJeQetyYYiD0sqVkKpiMIyAaOFqPwr0jLK7A1Ed7N-pxBnXShAbUVHlTKKzcM0oXNur3uWt7VlbCJJTt3hUTS0CX1XxIBgjx7HQG3tn92PSVLS_QydGjk6hwJY1jdIox4dhwMo8Y/s1600/Create_File_Dialog_CRXDE.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA-xGoJeQetyYYiD0sqVkKpiMIyAaOFqPwr0jLK7A1Ed7N-pxBnXShAbUVHlTKKzcM0oXNur3uWt7VlbCJJTt3hUTS0CX1XxIBgjx7HQG3tn92PSVLS_QydGjk6hwJY1jdIox4dhwMo8Y/s1600/Create_File_Dialog_CRXDE.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUVNCTJPtUWtyssObQ5pMSjeNA-JEPEI9iNEJCd6FsFDOAczg2t5m_4At77hipvDbk-SncCpo5BAdHLLLXNy6VRYvEirQG15VB9vH5vN_cN9-vpIi7CwVPzWUGYVlEnuuKFz2tPj6Eor0/s1600/Create_SiteMap_CRXDE.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUVNCTJPtUWtyssObQ5pMSjeNA-JEPEI9iNEJCd6FsFDOAczg2t5m_4At77hipvDbk-SncCpo5BAdHLLLXNy6VRYvEirQG15VB9vH5vN_cN9-vpIi7CwVPzWUGYVlEnuuKFz2tPj6Eor0/s320/Create_SiteMap_CRXDE.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgskLwq-je-OOExHTGzbJas0jeQfGP1i5GPaMdya_Hzktc4ENZ2aayOR2_ipY8GCqwRTjr3hDLZRdzV6yV2LfFRHWH0HsDNm1cCJqBJgDeN7PPOE9Bf7sCxBfVAzSyGg4wyDPk3s3ppCXo/s1600/Site_File_CRXDE.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgskLwq-je-OOExHTGzbJas0jeQfGP1i5GPaMdya_Hzktc4ENZ2aayOR2_ipY8GCqwRTjr3hDLZRdzV6yV2LfFRHWH0HsDNm1cCJqBJgDeN7PPOE9Bf7sCxBfVAzSyGg4wyDPk3s3ppCXo/s1600/Site_File_CRXDE.png" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio3DFc2kPhZR4Gaci3RS0sPLTlSGworJpYcxOek8TApvtW3aJrNkc70m2j7KvD2wsgVH2__WiP0frKcbYn_dNjftUy4w-3JHZa3W2ZcPX84Z-OpWJCVvH5IFkNzAmTXqjogHXteabDacM/s1600/Site_File_Eclipse.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio3DFc2kPhZR4Gaci3RS0sPLTlSGworJpYcxOek8TApvtW3aJrNkc70m2j7KvD2wsgVH2__WiP0frKcbYn_dNjftUy4w-3JHZa3W2ZcPX84Z-OpWJCVvH5IFkNzAmTXqjogHXteabDacM/s1600/Site_File_Eclipse.png" /></a></div>
<br />
Then you can configure sling rewriter (org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl.xml) under /apps/sling/config to redirect to correct robots.txt or any site specific configuration. More information about configuration can be obtained from here <a href="http://www.wemblog.com/2012/10/how-to-work-with-configurations-in-cq.html" target="_blank">http://www.wemblog.com/2012/10/how-to-work-with-configurations-in-cq.html</a><br />
<br />
For Prod something like <span class="s1">resource.resolver.virtual</span><span class="s2">=</span>"[/robots.txt:/robots-prod.txt] and for all other env<br />
<br />
<div class="p1">
<span class="s1"> </span><span class="s2">resource.resolver.virtual</span><span class="s1">=</span>"[/robots.txt:/robots-qa.txt]"</div>
<div class="p1">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJrwRGRCqwk-hXTeN_FGrjkrBERhzfIAI_wMR5bx_Sg3XFC12RbiLVuGFfbPyfJgHwVpXoCIMql-Fzehmaq5QDxXOHWoeRPM9ob7jIIUdqIj15QE7w0eQAdgXiT8ZA38Fnd1LjB6G2LrI/s1600/Create+Custom+Rewrite+for+Robots.txt.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJrwRGRCqwk-hXTeN_FGrjkrBERhzfIAI_wMR5bx_Sg3XFC12RbiLVuGFfbPyfJgHwVpXoCIMql-Fzehmaq5QDxXOHWoeRPM9ob7jIIUdqIj15QE7w0eQAdgXiT8ZA38Fnd1LjB6G2LrI/s640/Create+Custom+Rewrite+for+Robots.txt.png" width="640" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJrwRGRCqwk-hXTeN_FGrjkrBERhzfIAI_wMR5bx_Sg3XFC12RbiLVuGFfbPyfJgHwVpXoCIMql-Fzehmaq5QDxXOHWoeRPM9ob7jIIUdqIj15QE7w0eQAdgXiT8ZA38Fnd1LjB6G2LrI/s1600/Create+Custom+Rewrite+for+Robots.txt.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a></div>
<div class="separator" style="clear: both; text-align: left;">
For site specific configuration you can use something like</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div style="background-color: white; border-collapse: collapse; border-spacing: 0px; border: 0px; color: #333333; font-family: adobe-clean, 'Helvetica Neue', Arial, sans-serif; font-size: 14px; line-height: 21px; list-style: none; outline: 0px; padding: 0px; word-wrap: break-word;">
/apps/map.publish/www-robots.txt</div>
<div style="background-color: white; border-collapse: collapse; border-spacing: 0px; border: 0px; color: #333333; font-family: adobe-clean, 'Helvetica Neue', Arial, sans-serif; font-size: 14px; line-height: 21px; list-style: none; outline: 0px; padding: 0px; word-wrap: break-word;">
jcr:primaryType = "sling:Mapping" (that's the type when you create a new node)</div>
<div style="background-color: white; border-collapse: collapse; border-spacing: 0px; border: 0px; color: #333333; font-family: adobe-clean, 'Helvetica Neue', Arial, sans-serif; font-size: 14px; line-height: 21px; list-style: none; outline: 0px; padding: 0px; word-wrap: break-word;">
sling:internalRedirect = "/content/robots-prod.txt"</div>
<div style="background-color: white; border-collapse: collapse; border-spacing: 0px; border: 0px; color: #333333; font-family: adobe-clean, 'Helvetica Neue', Arial, sans-serif; font-size: 14px; line-height: 21px; list-style: none; outline: 0px; padding: 0px; word-wrap: break-word;">
sling:match = "http/www.SITE.com/robots.txt"</div>
<div style="background-color: white; border-collapse: collapse; border-spacing: 0px; border: 0px; color: #333333; font-family: adobe-clean, 'Helvetica Neue', Arial, sans-serif; font-size: 14px; line-height: 21px; list-style: none; outline: 0px; padding: 0px; word-wrap: break-word;">
<br /></div>
<div style="background-color: white; border-collapse: collapse; border-spacing: 0px; border: 0px; color: #333333; font-family: adobe-clean, 'Helvetica Neue', Arial, sans-serif; font-size: 14px; line-height: 21px; list-style: none; outline: 0px; padding: 0px; word-wrap: break-word;">
</div>
<br />
You might have to do some tuning on dispatcher for make this work. Feel free to ask any question.</div>
Yogihttp://www.blogger.com/profile/13222275932054732457noreply@blogger.com8