You can integrate Adobe Experience Manager and Adobe Campaign Standard (referred to as Adobe Campaign for rest of the article) to create business solutions that require newsletters promoting a new product or service. For example, assume that you want to create an email campaign to raise awareness of the product. Using AEM and Adobe Campaign, you can address this use case by creating a AEM newsletter using AEM components such as text and image components. Then you can import the AEM newsletter into Adobe Campaign and use that newsletter in an email campaign.
↧
Integrating Adobe Experience Manager and Adobe Campaign Standard to create Newletters
↧
AEM & eCommerce Integration
One of the core elements of any eCommerce implementation is the management of product data. When integrating with AEM you have the choice of either importing the product data into the JCR or having it exist solely in the eCommerce system. There are pros and cons to both approaches. Importing the data into AEM allows you to make use of the AEM Commerce components, use the AEM Commerce API, and do some fun things like product page generation, and data-driven tag creation. Having the product data in the JCR also allows AEM to access the information without having to make a call to the commerce platform every time. The con of having this data in AEM is that it may present challenges in keeping the data in sync. While things like product name, description, and image may not change often some more dynamic properties such as stock level, pricing, and active status may demand a more real time approach. This challenge can possibly be offset through the use of incremental imports and node listeners but ultimately the decision will come down to your specific implementation and the needed frequency for updates.
I have encountered two ways to import product data into the JCR. The first method of importing products is accomplished by uploading good ol’ fashioned CSV files with your product data in AEM Tools at http://localhost:4502/miscadmin. Navigate to /etc/commerce/products, click “New File..”, then browse and select the CSV.
After your files have been uploaded, navigate to the AEM Product Importer interface. This is accessible via the following links for classic UI and touch UI respectively:
This is the generic importer interface as evidenced by the “Geometrixx” option for commerce provider. If you do not want to use the provided Geometrixx importer you will need to install custom code for your particular commerce provider and select it from the drop down. You then browse to the location of the CSV within the JCR that you uploaded previously and click “Import Products”.
The second method I’ve used is very similar to the first. For hybris, rather than uploading CSV files, by installing the hybris commerce bundle, you gain access to a similar importer customized for hybris:
This importer pulls product data directly from hybris without the need of an additional export step. In order for this to work, you will need to install and configure the connection within OSGi and, within the importer, enter the name of the catalog you wish to import from hybris.
I’m sure there are more methods/importers out there for the eCommerce platforms I haven’t worked with yet but I’d assume they function very similarly to the ones I’ve mentioned.
For both importers (at least in Classic UI mode) you will enter a store name. This store name will dictate where in the JCR the product data will be stored following the pattern /etc/commerce/products/storename. How this product data looks after import can be seen within Geometrixx or in a much more tasty example in the screenshot below.
The products are organized under nodes of the type sling:Folder. Under the sling:Folder we have the base product. The base product will have the following properties:
- jcr:primaryType – nt:unstructured
- sling:resourceType – commerce/components/product
- cq:commerceType – product
In addition there should be an identifier that should be unique to that product. Other product data you will often finder on these base product nodes are jcr:title, jcr:description, and price. Also note the image node under the base product. This node has a sling:resourceType of commerce/components/product/image and a fileReference with the path to the product image. This is not required and, depending on your import configuration and needs, you may have the image path exist as a property on the product node.
The children of the base product are referred to as variants. These represent the different options a customer will have when viewing information for or ordering the product. A base product may have several variants or it may have none at all. In the screenshot above we have the property cq:productVariantAxes with a value of flavor. Typically I’ve seen this value be color or size and allows us to have variation specific data in the JCR.
The product variant, like the base product, will have the properties:
- jcr:primaryType – nt:unstructured
- sling:resourceType – commerce/components/product
The variants differ in that the cq:commerceType will have a value of variant and will also have a value for a property that corresponds to the cq:productVariantAxes value on the base product. In the case above, this property is flavor but will most likely be color or size in most implementations. Like a given product can have multiple available colors and each color can have multiple available sizes a base product can have multiple variants with each of those variants having variants as well. In these cases the cq:productVariantAxes would have an additional value as shown below.
Additional information can be found here:
↧
↧
AEM and Hybris Integration
Developing with Hybris
The eCommerce framework can be used with any eCommerce solution. Certain specifics and examples dealt with here will refer to the hybris solution.
The integration framework includes an integration layer with an API. This allows you to:
- plug in an eCommerce system and pull product data into AEM
- build AEM components for commerce capabilities independent of the specific eCommerce engine
↧
Translating Content for Multilingual Sites
Automate the translation of page content, assets, and user-generated content to create and maintain multilingual websites. To automate translation workflows, you integrate translation service providers with AEM and create projects for translating content into multiple languages. AEM supports human and machine translation workflows.
↧
Extending the Multi Site Manager using the Experience Manager MSM API
You can use the Adobe Experience Manager Muli Site Manager (MSM) API to create a custom service that is invoked when you perform a MSM operation such as create and activate a LiveCopy page. Multi Site Manager enables you to easily manage multiple web sites that share common content. MSM lets you define relations between the sites so that content changes in one site are automatically replicated in other sites.
For example, web sites are often provided in multiple languages for international audiences. When the number of sites in the same language is low (three to five), a manual process for syncronizing content across sites is possible. However, as soon as the number of sites grows or when multiple languages are involved, it becomes more efficient to automate the process.
A service that works with Experience Manager MSM functionality is implemented as an OSGi bundle and uses APIs located in the com.day.cq.wcm.api package.
↧
↧
Explore Request Log in AEM
Request log in AEM plays a very vital role towards analysis of site performance. For each request and response one entry is written into request.log file, you can analyze this log file to find out maximum time taken by a request to load and then troubleshoot the issue to increase overall site performance.
↧
AEM Deployment with Jenkins
In this article, I am going to explaing how to deploy aem packages using Jenkins, The Jenkins can be used as a continuous integratiion server using which we can deploy packages automatically on either author or publish instances of a AEM development and qa envrionment’s, I dont recommed to install it on production envrionment, we can do lot of things with Jenkins, we can configure notifications when build fails and also using plugin’s we can connect to different version control systems such GIT, SVN etc…
Here, I am going to cover how to deploy AEM builds using Jenkins, the first thing which we need to do is download and install Jenkins from this link
Once the Jenkins is installed then the next step is go to dashboard of Jenkins and install plugins as part of this I have installed Maven plugin
In the dashboard left navigation there is an item called “Manage Jenkins”click on this, on the Manage Jenkins screen you will find Manage Plugins link
↧
Repository Size Growing Rapidly in AEM 6
It's possible that wrong filters may have been applied, too many nodes were created, or huge renditions were also produced. Other times, it may even be a bug. In any case, Adobe has released the offline compaction method last year which is working great, and they also introduced the online compaction method. Online compaction allows you to trigger a repository compaction from within a running AEM instance via the brand new Operations & Maintenance Dashboard. It also lets you easily schedule it to ensure you have no performance hits during peak usage. Actions in the Dashboard can also be triggered via other means besides the web browser so automation of various processes is a goal that can now be achieved.
Online compaction
Before running any compactions make sure you have a consistent backup you can easily restore to in case its needed. These features are hot off the press!
1. First, get the latest hotfix of Oak which provides you this functionality from the package share for AEM 6.0 (Oak 1.0.22), with AEM 6.1 (Oak 1.2.7) it is built in!
2. Install it (there is a restart of AEM required afterwards) don't restart just stop after it is finished (make sure you tail the logs!)
3. ssh into your machine and use the oak-run.jar matching your oak version to clean up old checkpoints
4. To clean up the checkpoints follow the steps below java -jar oak-run.jar checkpoints install-folder/crx-quickstart/repository/segmentstore
java -jar oak-run.jar checkpoints install-folder/crx-quickstart/repository/segmentstore rm-all
5. Now start your AEM again and go to the system console -> JMX -> search for "CompactionStrategy"
6. Make sure the PausedCompaction is set to false as well as CloneBinaries
7. Go to the maintenance dashboard -> http://localhost:4502/libs/granite/operations/content/maintenance/window.html/mnt/overlay/granite/operations/config/maintenance/_granite_daily
8. On there trigger the revision cleanup and tail to logs for progress
9. The log's will tell you how much it cleaned up but you can allways check with -> du -h --max-depth=1 and compare before and after results of your repository folder
If your curious about more functionality (backup etc.) of the oak-run.jar have a look on the jackrabbit github -> https://github.com/apache/jackrabbit-oak/tree/trunk/oak-run

Offline compaction
Offline compaction can be used any time the AEM instance is stopped. This is also a prerequisite to running online compaction if you haven't removed old checkpoints previously.
To see the full effect of the online compaction later, just remove the checkpoints and don't actually run the offline compaction.
- Stop your AEM instance
- Use the oak-run.jar tool to find any old checkpoints -> download -> http://mvnrepository.com/artifact/org.apache.jackrabbit/oak-run
java -jar oak-run.jar checkpoints your-install-folder/crx-quickstart/repository/segmentstore
- Next, delete the unreferenced checkpoints
java -jar oak-run.jar checkpoints your-install-folder/crx-quickstart/repository/segmentstore rm-all
- The final step is to run the compaction and wait for it to complete (tail the logs!)
java -jar oak-run.jar compact your-install-folder/crx-quickstart/repository/segmentstore
Closing words of wisdom
Make sure you keep track of repository growth as it can easily impact performance or cause a possible outage of the instance due to the system running out of storage space.
With AEM 6, Service Pack 1 and Service Pack 2 are a necessity and should be installed. The later hotfix mentioned applies the latest Oak Fixes and raises it to a version of 1.0.11 of the Oak Core.
Note that some Service Packs and Hotfixes, such as the one for Oak, require a restart! Ensure it gets thoroughly tested beforehand, and plan it into your continuous release cycle for the next deployment to stay up to date.
UPDATE 16.03.2015:
1. If interested in details of the hotfixes have a look on Adobes Hotfix Page
2. A new Hotfix 5916 was released which addreses some possible issues with the Oak garbage collection
↧
OSGi Configuration via JCR Nodes
The reasons to configure OSGi services via content nodes is obvious:
- Configurations are deployed with the code
- Configurations can be transferred with content packages
- Configurations can be managed with source control
Defining an OSGi configuration with content nodes is pretty simple:
You create a sling:Folder 'config' and add nodes below it of type sling:OsgiConfig. This node has to have the name of the persistence ID, usually that's the fully qualified class name of the service you want to configure, e.g. com.day.cq.wcm.core.impl.VersionManagerImpl.
Therefore, you can configure the service with an xml file in the folder /apps/yourproject/config with the name com.day.cq.wcm.core.impl.VersionManagerImpl.xml and the following content:
<?xml version="1.0" encoding="UTF-8">
<jcr:root
xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primartyType="sling:OsgiConfig"
versionmanager.maxNumberVersions="{Long}5"
versionmanager.ivPaths="/"
versionmanager.purgePaths="[/etc/feeds,/home/users/public,/home/groups/public]"
versionmanager.createVersionOnActivation="{Boolean}true"
versionmanager.maxAgeDays="{Long}3"
versionmanager.purgingEnabled="{Boolean}true" />
You can add factory configurations (multiple settings for one configuration) by adding a unique identifier to the file name, separated by a hyphen. Setting up the MCM configuration e.g. can be done by providing a file named com.day.cq.mcm.impl.MCMConfiguration-myConfiguration.xml. This will create a binding to the configuration.
Only one open topic remains: You usually have one code base, but multiple configuration according to the various systems: An integration test author system has different configurations compared to a production publish system. The instances can be distinguished by using different runmodes, and the configurations can be runmode specific as well:
Just add the name of the runmode the set of configurations apply to the config-folder, like 'config.author' or 'config.publish'. By this you can maintain all applicable configurations in the version control, deploy the code, activate the packages - and the instance itself picks the proper settings. Pretty neat, isn't it?
↧
↧
Scaffolding in AEM
Scaffolding is a functionality to create structure-wise similar content based on a - well - old-fashioned form-based input screen. Boring, you might say, and definitely nothing any editor used to drag'n'drop fun would like to use. Especially, since swapping back and forth to scaffolding mode from the sidekick doesn't work properly if the content structure changed by e.g. adding new components or removing / re-adding the text-image. Still, if there's some casual user who just once in a while has to type in some news entry or blog post, that scaffold might work - sort of. But the scaffold is not much to talk about. Let's reconsider this.
What is scaffolding actually? Basically, it's form based editing of existing or new pages. The form is defined as a static dialog within the CMS. You can have a look at the example and the dialog definition in your CQ5.5 instance (links require running it on localhost:4502).
This scenario can be used not only for quickly creating structured content (and works quite well for that use case), but I also used the functionality of the scaffold to provide advanced functionality:
- Assume you have configuration and administration pages, which do not require a paragraph system (i.e. only single values or 'trivial' multi-field values). You could create an admin page with a component on it, and the editor has to hit the edit button to actually change something - or you enable him to edit directly in the page using the scaffold.
- You can also generate pages which go beyond some regular content page. For example I wrote a small scaffold for newsletters. The scaffold page can be linked to directly, and someone can easily create a newsletter entry without understanding how CQ5 works at all. Standard content like the from address, header, footer and so on can be easily provided by hidden fields.
- The scaffold clearly shows metadata which may be hidden from the regular editor, so the scaffold can be used perfectly for validation purposes within a publication workflow - e.g. highlighting the often forgotten page properties, which hold important SEO information.
- I've never done it but I think it could also be used for post-processing of form-based submits.
So there are some use cases which make the scaffolding quite interesting. One other thing is that the scaffold is extendable:
- One limitation of the scaffold is that it's using a static dialog. If you create your news entry page with the scaffold, then add a new paragraph to that page and return to the scaffold - that content won't be editable as it is not covered by the static dialog. Once I replaced the static scaffold dialog with a script iterating over each and every component on the page, resolving the dialog associated to the resource type of the content and doing some post processing to re-layout e.g. tabs into the appropriate containers within the scaffold. A true switch between WYSIWYG editing and the scaffold was possible. Also think about combining dynamic scaffolds with the review process - suddenly it's so easy to see if all images have alternate tags. I didn't integrate the parsys functionality into the scaffold page, so it was not possible to add new paragraphs in scaffolding mode. You could do that as well for sure ... One issue with the dynamic scaffold is initial creation of pages, as the first page is empty and therefore creating a new page via scaffold is impossible. But you can provide an initial set of content within the template definition, so the static dialog is completely obsolete.
- Taking it even further - if you really do not use external / automatic translation services: I once put two scaffolds in a side-by-side view, the left showing the original and the right the target language. Easiest interface possible for translators, and again: all the metadata often escaping the eyes is clearly visible. You don't get diffing though, or you have to have the 'real' rendition on the left - which will break alignment. But there certainly are ways to circumvent this.
↧
Enable SSL for AEM author instance
Accessing site over https is must. AEM has capability to access entire site or few pages https.
There are two ways to access site or pages by https:
- Using OSGI service Apache Felix Jetty Based Http service. (To access entire instance using https).
- Using crxde, manually creating nodes. (To access few pages using https).
Create credential for SSL development
Use the Java keytool to create a self-signed credential and to store it in a keystore file. The following procedure uses a single command that includes all of the information needed to create the keystore. For complete information about the command, see the Oracle Java SE Documentation.
- Create a directory named ssl in the directory where the quickstart JAR file is located.
- In the command prompt, type the following command to create the credential and keystore:
keytool -genkeypair -keyalg RSA -validity 3650 -alias cqse
-keystore [quickstart_dir]/ssl/keystorename.keystore -keypass key_password
-storepass storepassword -dname "CN=Host Name, OU=Group Name,
O=Company Name,L=City Name, S=State, C=Country_ Code"
The following example generates a private/public key pair with the following properties:
- alias: cqse
- keystore file: keystorename.keystore
- key password: password
- keystore password: password
keytool -genkeypair -keyalg RSA-validity 3650-alias cqse
-keystore D:/kishore/CQ5/AEM6.1/ssl/keystorename.keystore
-keypass password -storepass password -dname "CN=sbroders-w7,
OU=CQ, O=AEMQuickstart, L=HYD, S=TG, C=IN"
Through OSGI service Apache Felix Jetty Based Http Service
Through OSGI service Apache Felix Jetty Based Http Service. [Move entire author or publish instance to https]
- Go to Felix console system configurations http://localhost:4502/system/console/configMgr
- Search for Apache Felix Jetty Based Http Service.
- Open Apache Felix Jetty Based Http Service configuration. Enter below details
- Click Save
- Note:- If you get an ajax error on saving check error logs and make sure you are not getting error of port already in use. If port is not available try saving the configuration with some other port name.
Now your AEM instance can be opened over SSL.
Through crxde by manually creating the node.
Through crxde by manually creating the node. [Move selected pages of author instance to https]
- How to configure SSL on Author Instance.
- How to force cq to use ssl port.
Lets understand how to enable http over ssl in aem or how to enable https in aem with the help of a use case.
Use Case: For example if you want all pages of Geometrix’s outdoor to be open in http port but the pages under ‘men’ hierarchy to be open using secure https port.
Below image describes the usecase
Enable SSL on the Author Instance
Configure the Apache Felix Jetty-based HTTP service to use SSL, employing your certificate.
- Open CRXDE Lite and select the /apps folder. Click Create > Create Folder to create a folder named system (http://localhost:4502/crx/de).
- Below the system folder create a folder named config.author.
- Select the /apps/system/config.author node.
- Click Create > Create Node and enter the following properties:
- Name: org.apache.felix.http
- Type: sling:OsgiConfig
- Add properties to the node according to the following table:
Name Type Value org.apache.felix.https.enable Boolean true org.osgi.service.http.port.secure Long 5433 org.apache.felix.https.nio Boolean true org.apache.felix.https.keystore String [quickstart_dir]/ssl/cqkeystore.keystore org.apache.felix.https.keystore.password String password. org.apache.felix.https.keystore.key String alias e.g. cqse org.apache.felix.https.keystore.key.password String password. org.apache.felix.https.truststore String Path to truststore org.apache.felix.https.truststore.password String Truststore password. (Optional) org.apache.felix.https.clientcertificate String Defaults to none - Click Save All.
Forcing the Use of the SSL Port
- Go to /etc folder.
- Create a new sling:folder with name as map.
- Now under /etc/map create http node of type sling:folder.
- Under that create a node
- Name – localhost.4502
- Type– sling:mapping.
- Add below properties to this node:
- Name: sling:redirect Type : String Value : https://localhost:5404
- Name: sling:match Type : String Value : content/geometrixx-outdoor/en/men/(.*).html
- Click Save ALL , your all pages will be automatically open with https domain .
Below hierarchy explains above steps more clearly:
↧
Integrate Adobe AEM with Salesforce
Adobe AEM provide its extendable capabilities to integrate with other products. Below demonstration describe how to connect Adobe AEM with Salesforce which is the market’s leading cloud based CRM System. AEM provide OOTB components for the integration purpose. It helps the organization to target the customers through web channels as per their status in CRM.
Steps to Connect to Salesforce:
AEM uses OAuth mechanism to connect to Salesforce. So , first we need to create an connected app inside salesforce to get customer secret and access token.
Go tologin.salesforce.com. Click on Setup on the top right corner. Search for Apps and create a custom app. Fill in required details as shown in below images. Callback Url here accept only https urls, so our AEM must be SSL configured. Check here how to configure SSL in AEM. Callback url is the url of cloud service that we will create in AEM.
Create new custom app |
Fill in the required details.
Select an image for your app.
Choose the required tabs for your custom app.
Choose the user profile for which the custom app will be visible in the Force.com AppExchange menu. You can make a custom app as the default custom app of the profile. If a custom app is set as the default for a profile, then you cannot make it invisible for that profile.
Create a new connected app.
Search for apps in setup. Goto apps, scroll down to Connected apps section and create a new connected app.
- Fill all the required fields.
- Enable OAuth settings
- Enter the callback url. Callback url should be HTTPS. Check here how to enable HTTPS in AEM.
- Select the OAuth scopes. Connection may not be established if scopes are not selected appropriately. Connection was not successful when I have selected only "Full Access". So I selected all the OAuth scopes.
- Click on Manage button and Enable IP relaxation.
- Take a note of consumer key and consumer secret. We need to enter these values in Salesforce cloud configuration in AEM.
Thats all your salesforce app is create. Now lets establish connection from AEM to Salesforce.
Create a salesforce cloud configuration:
Login to your AEM instance and navigate to http://localhost:4502/miscadmin#/etc/cloudservices/salesforce. Click on new and create a new cloud configuration.
Double click on the newly created cloud service configuration to edit. Login url will be auto populated on the dialog. Enter customer key and customer secret and click on connect to salesforce. If connection is successful, then success alert will be displayed as shown below.
Troubleshooting:
- Callback url should be HTTPS. Check here how to enable HTTPS in AEM.
- Callback URL should be fully qualified path of your configuration page with extension.
- If we get this error response{"error":"invalid_grant","error_description":"authentication failure"} then check the authorization_url value. This value is hardcoded in the dialog in connector. So when we try to connect to ****.salesforce.com it tries to establish connection to login.salesforce.com.
- Adobe saleforce connector uses TLS 1.0 to connect to salesforce. Salesforce disabling TLS 1.0. Salesforce is requiring an upgrade to TLS 1.1 or higher by July 22, 2017. After clicking connect to salesforce, check browser console logs to see if any errors.
- Salesforce connector may not be able to connect succesfully if AEM is behind a proxy. Enable proxy in Open Day Commons HTTP Client 3.1 and Apache HTTP Components Proxy Configuration.If that doesn't work then you may need to extend the connector and modify SalesforceClient.java.
- Salesforce takes 5-10 min to enable the app after creation, so connect CQ with Salesfore after that.
By now you will be able to establish connection to Salesforce.
↧
ResourceResolver in AEM
ResourceResolver is one of the powerful API provided by Sling. Its job is to return resource object based on the given input, which can be path to the resource, query or parent resource to get its children. Resource resolver objects can be accessed through the following ways
- ResourceResolverFactory
- Request processing servlet through the SlingHttpServletRequest.getResourceResolver() method.
- WCMUsePojo / WCMUse in case of Sightly using the getResourceResolver()
Resource is accessible to the provided resolver is purely depends on the privilege to the resource resolver. getResourceResolver() from SlingServeletRequest / WcmUsePojo returns the resolver associated with the current request. On the other hand ResourceResolverFactory instanciate ResourceResolver using getSreviceResourceResolver method.
Resource resolver is not thread safe
ResourceResolver is not a thread safe object, it must be used in a threadsafe manner or proper synchronization should be adopted. It means resolver, returned resources or objects by adapting resolver / a resource should be synchronized if it is being accessed by multiple resources concurrently.
But why is it so, reason is simple, an instance to the Resolver creates a session to the repository to access the resources and resource is parsed into the sling object. When jcr session is saved or resource resolver is committed, the state of the sling object is updated to the resource of repository connected via session. Having multipile objects connected to single session would create a confusion that which should be considered as a source of truth.
Access to the Resource
Resolver defines two kinds of methods to access the resources based on the certain path
resolve : It takes parameter as an absolute path, resolves and return the resource based on the provided path. Return ROOT if null is passed as parameter. If path is relative the it is assumed that the path is relative to the root by prepending the slash if it is not there. It retruns NonExistingResource if resource is not found. It is useful when you have a request which need to be resolved into a resource.
Resource resolver is not thread safe
ResourceResolver is not a thread safe object, it must be used in a threadsafe manner or proper synchronization should be adopted. It means resolver, returned resources or objects by adapting resolver / a resource should be synchronized if it is being accessed by multiple resources concurrently.
But why is it so, reason is simple, an instance to the Resolver creates a session to the repository to access the resources and resource is parsed into the sling object. When jcr session is saved or resource resolver is committed, the state of the sling object is updated to the resource of repository connected via session. Having multipile objects connected to single session would create a confusion that which should be considered as a source of truth.
Access to the Resource
Resolver defines two kinds of methods to access the resources based on the certain path
resolve : It takes parameter as an absolute path, resolves and return the resource based on the provided path. Return ROOT if null is passed as parameter. If path is relative the it is assumed that the path is relative to the root by prepending the slash if it is not there. It retruns NonExistingResource if resource is not found. It is useful when you have a request which need to be resolved into a resource.
- getResource : It can consider absolute as well as relative path. It provides the resource if absolute path is given, in case of relative path search path is applied. It returns Null is no resource is found. It is intended to use while working with the scripts where further resources are required.
Resolver comes with the following two methods to list out all immediate children of the given resource
- listChildren : Returns Iterator of the Resource objects loaded from the children of given resource. AEM does not specify what the child could be it is absolutely depending upon your implementation. You can also declare generic class in to specify the return of Iterator.
- getChildren : Only difference it have from the listChildren is that its return type is Iterable. .
Resolver also facilitates you to retrieve the resources from query using the following methods
- findResources : Searches for the resources based on the given query. It accepts query string and language in which query is formulated (In absence of language parameter it takes "xpath" as default) as a parameter. This method returns Iterator of Resource objects retrieved by the query.
- queryResources : It queries the repository by the given query. It also accepts query string and language in which query is formulated (In absence of language parameter it takes "xpath" as default) as a parameter. It returns Iterator of Map which is indexed by Column name and Column value is the JCR value object which is converted into corresponding Java object. It is useful when you need to perform some logic written purely in Java or the resources need to be used by some Java based library.
Commonly used classes adaptable to ResourceResolver
↧
↧
SAML configuration in AEM
Introduction to SAML
SAML is a data format which is used to exchange authenticationand authorization information between different systems. Multiplecontributors are intacts to perform authentication and eachcontributor plays its own role for authentication.
- IdP - IdP stands for identity assentation providerwhich is responsible for providing identifier of the user looking tointeract with the system. Apart from the authentication it assertsthe system that the user is known to them. System may also providethe information pertain to the user profile. You must have seen thatFacebook and Google are also plays role of IDP.
- User Database - User database maintains keeps allthe information of users and IdP interacts with it to authenticatethe user and extract the user information.
- Service provider - Service provider refers to anysystem or entity which is intended to provide the service and hidingall the complexity and details behind. User or system can interactwith the service once it proves its authentication. However this is adifferent story that what part of the system he is authorized tointeract.
So, what process these contributors areadopting to setup a SSO (Single sign on) authentication process
- User requests SP for login.
- SP responds with the redirect request to IdP.
- Browser goes to IdP where user logs in.
- IdP responds with SAML token and redirect back to the SP.
- Browser goes to SP with SAML token and telling that it hasbeen authenticated.
- Service provider communicates with the IDP and verifying thatSAML token.
- IdP tells SP that yeah, user has been authenticated.
- SP responds the browser with welcome page.
Prerequsite
Identification provider (IdP) : Assuming that the IdP server isin place and configured with the User DB. IdP server should beconfigured with the certificates so that service provider cancommunicate securely.
Steps to configure SAML with AEM :
Following steps need to be performed for successful configurationwith IdP.
- Register service provider (SP) with the Identityprovider (IdP) : Service provider should be registered with IdP,so that IdP can recognize the authentication request by Serviceprovider. IdP require the information in the form of metadata. Here isthe sample of the metadata which IdP would require. You need toprovide this information to the team managing IdP.
<md:EntityDescriptorxmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"entityID="http://localhost:4503/">
<md:SPSSODescriptorprotocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat/>
<md:AssertionConsumerServiceBinding ="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"Location="http://localhost:4503/saml_login "index="1" />
</md:SPSSODescriptor>
</md:EntityDescriptor>
- Above mentioned IdP metadata provides thefollowing information.
- Service provider entity Id : Everyservice provider needs to be uniquely identified by the IDP. IDPregisters the SP with the Entity Id. Later with the help of thisinformation IDP identifies that the requested SP.
- Redirect URL of service provider (SP): On authentication, IdP POSTs SAML response to this providedURL. This redirect URL should be written in a specific pattern, URLshould be followed by /saml_login. Eg. of redirect URL ishttp://localhost:4502/saml_login.
- Configure AEM with the Identificationprovider (IdP) information :To communicate through secured channel, IdPcertificate needs to be installed in AEM. You need to perform the following steps to in import certificate.For AEM 6.0
- Create the folder structure within “etc” in AEM- \/etc\/key\/saml
- Certificate upload can be executed through both GUI and curl.
Using curl commandcurl -u admin:admin -F idp_cert=<path toIdP Cert>\\<idp.cert> -F idp_cert@TypeHint=Binaryhttp://localhost:4503/etc/key/samlUsing Crx-deDouble click on “idp_cert”, as given in the diagram. Adialog box will appear to browse the certificate.Fig1. - IDP cert properties Browse the certificate then click OK.Fig2. - IDP cert For AEM 6.1- Add IdP public cert to AEM truststore
- Go to: http://localhost:4502/libs/granite/security/content/useradmin.html
- Select any user because TrustStore is global to AEM
- Create trust store by supplying the password & then manage trust store
- Upload the IdP certificate & make note of the certificate Alias
- Add SP key and certificate chain to AEM keystore (authentication-service)
- Go to: http://localhost:4502/libs/granite/security/content/useradmin.html
- Select authentication-service
- Create KeyStore by supplying the password
- If encrypting SAML assertions then go to manage KeyStore for uploading the private & public key
- Configure the SAML authentication handler in the web console
- Go to: http://localhost:4502/system/console/configMgr
- Search for Adobe Granite SAML 2.0 Authentication Handler
- Add a new handler configuration and alias here should match with step1.
- Configure Adobe Granite SAML 2.0 authentication handlerSAML can be configured through Felix console but it is advisable to configure through runmodes, so that reconfiguration is not required for different environment.
SAML Configuration attributes :
- Path :- Path where authentication handler to be applied.
- Path :- Path where authentication handler to be applied.
- IDP-Url : - IDP url where authentication request should be redirected.
- Service provider entity id :- This is the same Id which is shared with the IdP for the uniquely identification of service provider e.g. https://www.example.com.
- Default redirect: - URL where IdP should be redirected after This is useful if autocreate of the user is enabled. It gets the user from SAML attributes and if user does not exist then user gets created.
- User Id:- URL where IdP should be redirected after successful login.
- Group membership:- Name of the group to which user should belong to. Group should be available as a part of SAML attribute.
- Synchronized attributes:- List of attributes should be synchronized with the attributes available in SAML response.
- Logout URL:- Logout Url of the IdP, where logout request should be redirected from SP./li>
Fig3. - SAML Configuration attributes. - Configure Apache sling referrer filterAs we know that on successful authentication IdP redirects to the SP and posts SAML response. So, IdP URL must be added as Sling referrer. In absence of it you may encounter with the (403 Forbidden error).As we know that on successful authentication IdP redirects to the SP and posts SAML response. So, IdP URL must be added as Sling referrer. In absence of it you may encounter with the (403 Forbidden error).
Fig4. - Apache sling referrer filter configuration. - SAML debnugingSaml log is important to identify how it is doing at the AEM end. SAML Trace FF plugin:- As we know that SAML is browser driven not the server, so it becomes very important to trace at client end. It can also help to trace SAML request and response.If users are not yet synchronize with IdP, and you are expecting that the user should be created with SAML response as AEM is already configured. So, in this case you must check the SAML response and verify that the SAML response must have user attributes.
↧
Access OSGI service from the WCMUse-class in Sightly
OSGI service are very helpful once its comes to the development of a module. A Service can be used to perform small task like string operations to big like processing shopping cart. For developers who are shifting to Sightly for better development practices and taking advantage of AEM 6.x features, it might be a troublesome that how a OSGI Service can be accessed in Sightly module.
Zoom out a bit and you will be able to see things more clear. Here’s all that needs to be done,
- You have to create a OSGI service as usual by creating a interface and implementing it.
- Create a class extending WCMUse and get the instance of your OSGI service.
- Class created in step #2, use this in Sightly component to get the values / output
Let’s get started,
1. Create an interface name SightlyServiceInterface.java that will be implemented by our service
package com.aemquickstart.core.services;
publicinterface SightlySerivceInterface { String getDeveloperName(); String getDeveloperProfile(); String getDeveloperSkills(); String getDeveloperData(); }
2. Create a service class name SightlyService.java, define the method’s implementations
package com.aemquickstart.core.services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
@Component
@Service
publicclassSightlySerivceimplements SightlySerivceInterface {
Logger logger = LoggerFactory.getLogger(SightlySerivce.class);
@Override
publicString getDeveloperName() {
return"John";
}
@Override
publicString getDeveloperProfile() {
return"AEM Developer";
}
@Override
publicString getDeveloperSkills() {
return"JAVA, OSGI, HTML, JS";
}
@Override
publicString getDeveloperData() {
Stringname=this.getDeveloperName();
String profile =this.getDeveloperProfile();
String skills =this.getDeveloperSkills();
returnname+" is a "+ profile +", He is expert in skills like "+ skills;
}
}
3. Write class which extends WCMUse name Developer.java
package com.aemquickstart.core.services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.adobe.cq.sightly.WCMUse;
publicclassDeveloperextendsWCMUse {
Logger logger = LoggerFactory.getLogger(Developer.class);
protected String detail;
@Override
publicvoid activate() {
SightlySerivceInterface service = getSlingScriptHelper().getService(SightlySerivceInterface.class);
detail = service.getDeveloperData();
}
publicString getDetails() {
returnthis.detail;
}
}
- Line 15 :- Getting our service instance
4. Access values in Sightly component
OSGI service value:-
<div data-sly-use.info="com.aemquickstart.core.services.Developer">
${info.details}
</div>
↧
Salesforce: Can't refresh access token. Response: {"error":"invalid_grant","error_description":"token validity expired"}
Sometimes we may not be able to refresh the Salesforce access_token using the rest api and get below error in logs
28.03.2017 23:41:40.184 *ERROR* [0:0:0:0:0:0:0:1 [1490724696957] GET /content/training/en/salesforce/jcr:content/par/salesforcesearch.html HTTP/1.1] com.adobe.cq.mcm.salesforce.SalesforceClient Can't refresh access token. Response: {"error":"invalid_grant","error_description":"token validity expired"}
Root cause:
This issue is due to the "Refresh Token Policy"settings of the connected app is set to "Immediately expire refresh token"
Follow the below steps to resolve this issue:
28.03.2017 23:41:40.184 *ERROR* [0:0:0:0:0:0:0:1 [1490724696957] GET /content/training/en/salesforce/jcr:content/par/salesforcesearch.html HTTP/1.1] com.adobe.cq.mcm.salesforce.SalesforceClient Can't refresh access token. Response: {"error":"invalid_grant","error_description":"token validity expired"}
Root cause:
This issue is due to the "Refresh Token Policy"settings of the connected app is set to "Immediately expire refresh token"
Follow the below steps to resolve this issue:
- Goto setup -> Connected apps ->Manage Policies
- Select Refresh Token Policy as Refresh token is valid until revoked
↧
Adobe AEM curl commands
Run JCR query builder API:
Find “all” page references for a given image/asset in a jcr path. The below command will return in JSON format:
curl -s -u ${username}:${password} -X GET http://localhost:4502/bin/querybuilder.json?path=/content/my-site&1_property=fileReference&1_property.value=/content/dam/my-site/image.jpg&p.limit=-1*Note: -1 in the p.limit will return all page references else prints only 10.
You can also specify the required number of page references; something like below which will return only 20 page references:
curl -s -u ${username}:${password} -X GET http://localhost:4502/bin/querybuilder.json?path=/content/my-site&1_property=fileReference&1_property.value=/content/dam/my-site/image.jpg&p.limit=20To find all pending Jobs
curl -s -u admin:admin “http://localhost:4502/bin/querybuilder.json?&path=/var/eventing/jobs&type=slingevent:Job&p.limit=-1&fulltext=/com/day/cq/replication/job&fulltext.relPath=@slingevent:topic&property.and=true&property=slingevent:finished&property.operation=not&orderby=slingevent:created&orderby.sort=asc”To find all Blocking Jobs
curl -s -u admin:admin “http://localhost:4502/bin/querybuilder.json?path=/var/eventing/jobs/anon&type=slingevent:Job&rangeproperty.property=event.job.retrycount&rangeproperty.lowerBound=1”AEM Package Manager Commands:
Uninstall a bundle (use http://localhost:4502/system/console/bundles to access the Apache Felix web console)
curl -u admin:admin -daction=uninstall http://localhost:4505/system/console/bundles/”name-of-bundle”Upload a package AND install
curl -u admin:admin -F file=@”name of zip file” -F name=”name of package” -F force=true -F install=true http://localhost:4502/crx/packmgr/service.jspUpload a package DO NOT install
curl -u admin:admin -F file=@”name of zip file” -F name=”name of package” -F force=true -F install=false http://localhost:4502/crx/packmgr/service.jspRebuild an existing package in CQ
curl -u admin:admin -X POST http://localhost:4502:/crx/packmgr/service/.json/etc/packages/name_of_package.zip?cmd=buildDownload a package:
curl -u admin:admin http://localhost:4502/etc/packages/export/name_of_package.zip > name of local package fileUpload a package
curl -u admin:admin -F package=@”name_of_package.zip” http://localhost:4502/crx/packmgr/service/.json/?cmd=uploadInstall a package
curl -u admin:admin -X POST http://localhost:4502/crx/packmgr/service/.json/etc/packages/export/name of package?cmd=install
List contents of a package
$ curl -u admin:admin -X POST http://localhost:4502/crx/packmgr/service/console.html/etc/packages/day/cq561/product/cq-content-5.6.1.20130606.zip?cmd=contentsAEM Bundle Manager Commands:
Install a bundle
curl -u admin:admin -F action=install -F bundlestartlevel=20 -F bundlefile=@”name of jar.jar” http://localhost:4502/system/console/bundlesBuild a bundle
curl -u admin:admin -F bundleHome=/apps/ projects-A/bundles/name of bundle -F descriptor=/apps/projects-A/bundles/com.centrica.cq.wcm.core-bundle/name_of_bundle.bnd http://localhost:4502/libs/crxde/buildStop a bundle
curl -u admin:admin http://localhost:4502/system/console/bundles/org.apache.sling.scripting.jsp -Faction=stopStart a bundle
curl -u admin:admin http://localhost:4502/system/console/bundles/org.apache.sling.scripting.jsp -Faction=startJCR Node Management:
Delete a node (hierarchy) – (this will delete any directory / node / site)
curl -X DELETE http://localhost:4502/path/to/node/jcr:content/nodeName -u admin:adminCreate or add a JCR node:
curl -u admin:admin -F”_charset_=utf-8″ -F”:nameHint=node” -F”jcr:primaryType=nt:unstructured” -F”sling:resourceType=project-A/components/abc-definition” -F”nodeReferenceName=ref-name1″ -F”jcr:createdBy=bala” -F”jcr:lastModifiedBy=bala” http://localhost:4502/content/geometrixx/en_GB/products/jcr:content/abc/Create or add a JCR node along with some properties:
curl -u admin:admin -F”_charset_=utf-8″ -F”:nameHint=var” -F”jcr:primaryType=nt:unstructured” -F”key=key1″ -F”value=key1-value” http://localhost:4502/content/geometrixx/en_GB/products/jcr:content/abc/variables/CQ Replication Commands:
Tree Activation
curl -u admin:admin -F cmd=activate -F ignoredeactivated=true -F onlymodified=true -F path=/content/geometrixx http://localhost:4502/etc/replication/treeactivation.htmlUser & Group Administration
Get User Info:
curl -u admin:admin http://localhost:4502/libs/granite/security/balakondepudi.jsonCreate User:
curl -u admin:admin -FcreateUser= -FauthorizableId=testuser -Frep:password=abc123 http://localhost:4502/libs/granite/security/post/authorizablesCreate Group:
curl -u admin:admin -FcreateGroup=group1 -FauthorizableId=testGroup1 http://localhost:4502/libs/granite/security/post/authorizablesCreate user with Profile:
curl -u admin:admin -FcreateUser=testuser -FauthorizableId=testuser -Frep:password=abc123 -Fprofile/gender=male http://localhost:4502/libs/granite/security/post/authorizablesSet a Profile Property on an Existing User:
curl -u admin:admin -Fprofile/age=29 http://localhost:4502/home/users/t/testuser1.rw.htmlCreate a User as a Member of a Group:
curl -u admin:admin -FcreateUser=testuser -FauthorizableId=testuser -Frep:password=abc123 -Fmembership=contributor http://localhost:4502/libs/granite/security/post/authorizablesAdd a User to a Group:
curl -u admin:admin -FaddMembers=testuser1 http://localhost:4502/home/groups/t/testGroup.rw.htmlRemove a User from a Group:
curl -u admin:admin -FremoveMembers=testuser1 http://localhost:4502/home/groups/t/testGroup.rw.htmlSet a User’s Group Memberships:
curl -u admin:admin -Fmembership=contributor -Fmembership=testgroup http://localhost:4502/home/users/t/testuser.rw.htmlDelete user and Group:
curl -u admin:admin -FdeleteAuthorizable= http://localhost:4502/home/users/t/testusercurl -u admin:admin -FdeleteAuthorizable= http://localhost:4502/home/groups/t/testGroup
Change an user password:
curl -u testuser:OLD_PWD -F rep:password=”NEW_PWD” http://localhost:4502/home/users/t/testuser.rw.htmlcurl rep:password=”test” –user admin:admin http://localhost:4502/home/users/a/alister@geometrixx.com
Backup Commands:
Online Backup:
curl -u admin:admin -X POST http://localhost:4502/system/console/jmx/com.adobe.granite:type=Repository/op/startBackup/java.lang.String?target=<PATH-TO-BACKUP>/12-feb-2013.zipOnline backup with delay in milli seconds:
curl -u admin:admin -X POST http://localhost:4502/system/console/jmx/com.adobe.granite:type=Repository/a/BackupDelay?value=<TIME-IN-MILISECOND>curl -u admin:admin –data “delay=TIME-IN-MILISECONDS&force=false&target=01-dec-2012.zip” http://localhost:4502/libs/granite/backup/content/admin/backups/
How to stop a running online backup:
curl -u admin:admin http://localhost:4502/libs/granite/backup/content/admin/backups.cancel.htmlLink to track online progress:
http://localhost:4502/libs/granite/backup/content/admin.htmlDatastore GC:
For Datastore Garbage Collection:
curl -u admin:admin -X POST http://localhost:4502/system/console/jmx/com.adobe.granite:type=Repository/op/runDataStoreGarbageCollection/java.lang.BooleanTar Optimization:
curl -u admin:admin -X POST http://localhost:4502/system/console/jmx/com.adobe.granite:type=Repository/op/startTarOptimization/
curl -u admin:admin -X POST http://localhost:4502/system/console/jmx/com.adobe.granite:type=Repository/op/startTarOptimization/
Flush Dispatcher Cache:
curl -H “CQ-Action: Flush” -H “CQ-Handle: /content/geometrixx/en/products” -H “CQ-Path:/content/geometrixx/en/products” -H “Content-Length: 0” -H “Content-Type: application/octet-stream” http://dispatcher-server-hostname:port/dispatcher/invalidate.cache
curl -H “CQ-Action: Flush” -H “CQ-Handle: /content/geometrixx/en/products” -H “CQ-Path:/content/geometrixx/en/products” -H “Content-Length: 0” -H “Content-Type: application/octet-stream” http://dispatcher-server-hostname:port/dispatcher/invalidate.cache
↧
↧
Salesforce REST API implementation - JAVA
This post demonstrates the following basic use cases for the REST API:
- authentication with OAuth 2.0 (This is for development purposes only. Not a real implementation.)
- querying (using account records)
- inserting (using a contact record related to one of the retrieved account records)
- updating (updates contact record added in previous step)
Create an Inbound Integration Using the Force.com REST API
Sample Project
- authentication with OAuth 2.0 (This is for development purposes only. Not a real implementation.)
- querying (using account records)
- inserting (using a contact record related to one of the retrieved account records)
- updating (updates contact record added in previous step)
importjava.io.BufferedReader;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.IOException;
importjava.io.UnsupportedEncodingException;
importorg.apache.http.Header;
importorg.apache.http.HttpResponse;
importorg.apache.http.client.HttpClient;
importorg.apache.http.client.methods.HttpGet;
importorg.apache.http.client.methods.HttpPost;
importorg.apache.http.entity.StringEntity;
importorg.apache.http.impl.client.DefaultHttpClient;
importorg.apache.http.message.BasicHeader;
importorg.apache.http.util.EntityUtils;
importorg.json.JSONException;
importorg.json.JSONObject;
/**
* This program demonstrates the following basic use cases for the REST API:
* - authentication with OAuth 2.0 (This is for development purposes only. Not a real implementation.)
* - querying (using account records)
* - inserting (using a contact record related to one of the retrieved account records)
* - updating (updates contact record added in previous step)
*
*/
publicclassREST_CodeextendsObject {
//---------Credentials----------
//Credentials providing access to a specific Salesforce organization.
privatestaticfinalString userName ="demo@demo.com"; // COPY USERNAME
privatestaticfinalString password ="passwordTOKEN"; // COPY PASSWORD AND TOKEN
//---------REST and OAuth-------
//Portions of the URI for REST access that are re-used throughout the code
privatestaticStringOAUTH_ENDPOINT="/services/oauth2/token";
privatestaticStringREST_ENDPOINT="/services/data";
//Holds URI returned from OAuth call, which is then used throughout the code.
String baseUri;
//The oauthHeader set in the oauth2Login method, and then added to
//each HTTP object that is used to invoke the REST API.
Header oauthHeader;
//Basic header information added to each HTTP object that is used
//to invoke the REST API.
Header prettyPrintHeader =newBasicHeader("X-PrettyPrint", "1");
//----------Data specific---------
//Retrieved accountId that is used when contact is added.
privatestaticString accountId;
//Id of inserted contact. Used to update contact.
privatestaticString contactId;
//----------Utility-------------
//Used to get input from console.
privatestaticBufferedReader reader =newBufferedReader(newInputStreamReader(System.in));
//================Code starts here===================
publicstaticvoidmain(String[] args) {
newREST_Code();
}
/**
* This class holds all the values related to the credentials needed to
* make the OAuth2 request for authentication. Normally they would not be set in
* this manner.
*/
classUserCredentials {
String loginInstanceDomain ="cs10.salesforce.com"; // COPY YOUR SERVER INSTANCE
String apiVersion ="37"; // COPY YOU API VERSION
String userName =REST_Code.userName;
String password =REST_Code.password;
String consumerKey ="CONSUMER_KEY"; // COPY YOUR CONSUMER KEY
String consumerSecret ="CONSUMER_SECRET"; // COPY YOUR CONSUMER SECRET
String grantType ="password";
}
/**
* Constructor drives console interaction and calls appropriate methods.
*/
publicREST_Code() {
showMenu();
boolean invalidValue =true;
int executionOption =99;
String choice = getUserInput("Enter option: ");
while (invalidValue) {
try {
executionOption =Integer.parseInt(choice);
if ((executionOption <1|| executionOption >4) && executionOption!=99) {
System.out.println("Please enter 1, 2, 3, 4, or 99.\n");
choice = getUserInput("Enter the number of the sample to run: ");
showMenu();
} else {
invalidValue =false;
}
} catch (Exception e) {
System.out.println("Invalid value. Please enter 1, 2, 3, 4, or 99.\n");
choice = getUserInput("Enter the number of the sample to run: ");
showMenu();
}
}
if (executionOption ==99) {
System.out.println("No action taken");
} else {
//Login is done for option 1, as well as all other valid options.
this.oauth2Login();
if (executionOption >=2) {
this.restGetExample();
}
if (executionOption >=3) {
if (accountId !=null) {
this.restPostExample(accountId);
} else {
System.out.println("Account not found.");
}
}
if (executionOption ==4) {
if (contactId !=null) {
this.restPatchExample(contactId);
} else {
System.out.println("Contact not found.");
}
}
}
System.out.println("Program complete.");
}
/**
* This method connects the program to the Salesforce organization using OAuth.
* It stores returned values for further access to organization.
* @param userCredentials Contains all credentials necessary for login
* @return
*/
publicHttpResponseoauth2Login() {
System.out.println("_______________ Login _______________");
OAuth2Response oauth2Response =null;
HttpResponse response =null;
UserCredentials userCredentials =newUserCredentials();
String loginHostUri ="https://"+ userCredentials.loginInstanceDomain +OAUTH_ENDPOINT;
try {
//Construct the objects for making the request
HttpClient httpClient =newDefaultHttpClient();
HttpPost httpPost =newHttpPost(loginHostUri);
StringBuffer requestBodyText =newStringBuffer("grant_type=password");
requestBodyText.append("&username=");
requestBodyText.append(userCredentials.userName);
requestBodyText.append("&password=");
requestBodyText.append(userCredentials.password);
requestBodyText.append("&client_id=");
requestBodyText.append(userCredentials.consumerKey);
requestBodyText.append("&client_secret=");
requestBodyText.append(userCredentials.consumerSecret);
System.out.println("Response Body: "+requestBodyText.toString());
StringEntity requestBody =newStringEntity(requestBodyText.toString());
requestBody.setContentType("application/x-www-form-urlencoded");
httpPost.setEntity(requestBody);
httpPost.addHeader(prettyPrintHeader);
//Make the request and store the result
response = httpClient.execute(httpPost);
//Parse the result if we were able to connect.
if ( response.getStatusLine().getStatusCode() ==200 ) {
String response_string =EntityUtils.toString(response.getEntity());
try {
JSONObject json =newJSONObject(response_string);
oauth2Response =newOAuth2Response(json);
System.out.println("JSON returned by response: +\n"+ json.toString(1));
} catch (JSONException je) {
je.printStackTrace();
}
baseUri = oauth2Response.instance_url +REST_ENDPOINT+"/v"+ userCredentials.apiVersion +".0";
oauthHeader =newBasicHeader("Authorization", "OAuth "+ oauth2Response.access_token);
System.out.println("\nSuccessfully logged in to instance: "+ baseUri);
} else {
System.out.println("An error has occured. Http status: "+ response.getStatusLine().getStatusCode());
System.out.println(getBody(response.getEntity().getContent()));
System.exit(-1);
}
} catch (UnsupportedEncodingException uee) {
uee.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (NullPointerException npe) {
npe.printStackTrace();
}
return response;
}
/**
* This method demonstrates
* - How to use HTTPGet and a constructed URI to retrieve data from Salesforce.
* - Simple parsing of a JSON object.
*/
publicvoidrestGetExample() {
System.out.println("\n_______________ Account QUERY _______________");
try {
//Set up the HTTP objects needed to make the request.
HttpClient httpClient =newDefaultHttpClient();
String uri = baseUri +"/query?q=SELECT+id+,+name+FROM+Account+limit+1";
System.out.println("Query URL: "+ uri);
HttpGet httpGet =newHttpGet(uri);
httpGet.addHeader(oauthHeader);
httpGet.addHeader(prettyPrintHeader);
// Make the request.
HttpResponse response = httpClient.execute(httpGet);
// Process the result
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode ==200) {
String response_string =EntityUtils.toString(response.getEntity());
try {
JSONObject json =newJSONObject(response_string);
System.out.println("JSON result of Query:\n"+ json.toString(1));
accountId = json.getJSONArray("records").getJSONObject(0).getString("Id");
System.out.println("accountId value is "+ accountId);
} catch (JSONException je) {
je.printStackTrace();
}
} else {
System.out.println("Query was unsuccessful. Status code returned is "+ statusCode);
}
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (NullPointerException npe) {
npe.printStackTrace();
}
}
/**
* This method demonstrates
* - How to use HTTPPost and a constructed URI to insert data into Salesforce.
* - Simple creation of a JSON object.
*/
publicvoidrestPostExample(StringaccountId) {
System.out.println("\n_______________ Contact INSERT _______________");
String uri = baseUri +"/sobjects/Contact/";
try {
//create the JSON object containing the new contact details.
JSONObject contact =newJSONObject();
contact.put("LastName", "Polsani");
contact.put("FirstName", "Kishore");
contact.put("MobilePhone", "9999999999");
contact.put("Phone", "9999999999");
contact.put("AccountId", accountId);
System.out.println("JSON for contact record to be inserted:\n"+ contact.toString(1));
//Construct the objects needed for the request
DefaultHttpClient httpClient =newDefaultHttpClient();
HttpPost httpPost =newHttpPost(uri);
httpPost.addHeader(oauthHeader);
httpPost.addHeader(prettyPrintHeader);
// The message we are going to post
StringEntity body =newStringEntity(contact.toString(1));
body.setContentType("application/json");
httpPost.setEntity(body);
//Make the request
HttpResponse response = httpClient.execute(httpPost);
//Process the results
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode ==201) {
String response_string =EntityUtils.toString(response.getEntity());
JSONObject json =newJSONObject(response_string);
// Store the retrieved contact id to use when we update the contact.
contactId = json.getString("id");
System.out.println("New contact id from response: "+ contactId);
} else {
System.out.println("Insertion unsuccessful. Status code returned is "+ statusCode);
}
} catch (JSONException e) {
System.out.println("Issue creating JSON or processing results");
e.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (NullPointerException npe) {
npe.printStackTrace();
}
}
/**
* This method demonstrates
* - How to use HTTPPatch and a constructed URI to update data in Salesforce.
* NOTE: You have to create the HTTPPatch, as it does not exist in the standard library.
* - Simple creation of a JSON object.
*/
publicvoidrestPatchExample(Stringcontactid) {
System.out.println("\n_______________ Contact UPDATE _______________");
//Notice, the id for the record to update is part of the URI, not part of the JSON
String uri = baseUri +"/sobjects/Contact/"+ contactid;
try {
//Create the JSON object containing the updated contact phone number
//and the id of the contact we are updating.
JSONObject contact =newJSONObject();
contact.put("Phone", "(415)555-1234");
System.out.println("JSON for update of contact record:\n"+ contact.toString(1));
//Set up the objects necessary to make the request.
DefaultHttpClient httpClient =newDefaultHttpClient();
HttpPatch httpPatch =newHttpPatch(uri);
httpPatch.addHeader(oauthHeader);
httpPatch.addHeader(prettyPrintHeader);
StringEntity body =newStringEntity(contact.toString(1));
body.setContentType("application/json");
httpPatch.setEntity(body);
//Make the request
HttpResponse response = httpClient.execute(httpPatch);
//Process the response
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode ==204) {
System.out.println("Updated the contact successfully.");
} else {
System.out.println("Contact update NOT successfully. Status code is "+ statusCode);
}
} catch (JSONException e) {
System.out.println("Issue creating JSON or processing results");
e.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (NullPointerException npe) {
npe.printStackTrace();
}
}
/**
* Extend the Apache HttpPost method to implement an HttpPost
* method.
*/
privatestaticclassHttpPatchextendsHttpPost {
publicHttpPatch(Stringuri) {
super(uri);
}
publicStringgetMethod() {
return"PATCH";
}
}
/**
* This class is used to hold values returned by the OAuth request.
*/
staticclassOAuth2Response {
String id;
String issued_at;
String instance_url;
String signature;
String access_token;
publicOAuth2Response() {
}
publicOAuth2Response(JSONObjectjson) {
try {
id =json.getString("id");
issued_at = json.getString("issued_at");
instance_url = json.getString("instance_url");
signature = json.getString("signature");
access_token = json.getString("access_token");
} catch (JSONException e) {
e.printStackTrace();
}
}
}
//==========utility methods=============
/**
* Utility method for changing a stream into a String.
* @param inputStream
* @return
*/
privateStringgetBody(InputStreaminputStream) {
String result ="";
try {
BufferedReader in =newBufferedReader(
newInputStreamReader(inputStream)
);
String inputLine;
while ( (inputLine = in.readLine() ) !=null ) {
result += inputLine;
result +="\n";
}
in.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
return result;
}
//--------------utility methods for user input----------
/**
* A utility method to be used for getting user input from the console.
*/
privateStringgetUserInput(Stringprompt) {
String result ="";
try {
System.out.print(prompt);
result = reader.readLine();
} catch (IOException ioe) {
ioe.printStackTrace();
}
return result;
}
/**
* Outputs menu choices on console.
*/
privatevoidshowMenu() {
System.out.println("");
System.out.println("");
System.out.println(" 1. Login Only");
System.out.println(" 2. Find Account");
System.out.println(" 3. Insert Contact for Account");
System.out.println(" 4. Update Contact");
System.out.println("99. Exit");
System.out.println("");
}
}
Create an Inbound Integration Using the Force.com REST API
Sample Project
Screenshots:
↧
AEM Component is in satisfied state, not in active
Some times we face OSGI component is in active state when the component is installed for the first time. When we modify the component from configMgr, component state changes to satisfied.
To avoid this and make the component in active state add the annotation @Activate to the activate method. This helps in changing the component state to Active whenever the component is modified.
To avoid this and make the component in active state add the annotation @Activate to the activate method. This helps in changing the component state to Active whenever the component is modified.
↧
Encrypting and Decrypting String in Java
The Advanced Encryption Standard (AES), also known by its original name Rijndael (Dutch pronunciation: [ˈrɛindaːl]),[5][6] is a specification for the encryption of electronic data established by the U.S. National Institute of Standards and Technology (NIST) in 2001.[7]
Below is sample java code to encrypt and decrypt a string.
Below is sample java code to encrypt and decrypt a string.
packagecom.kishore;
importjava.io.UnsupportedEncodingException;
importjava.security.MessageDigest;
importjava.security.NoSuchAlgorithmException;
importjava.util.Arrays;
importjavax.crypto.Cipher;
importjavax.crypto.spec.SecretKeySpec;
importorg.apache.commons.codec.binary.Base64;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
publicclassEncrypt {
protectedfinalLoggerLOGGER=LoggerFactory.getLogger(this.getClass());
publicstaticvoidmain(String[] args) {
String encryptString ="45634634";
finalStringKEY="kishore";
Encrypt obj =newEncrypt();
String encryptedString = obj.encrypt(encryptString, obj.encryptSecretKey(KEY));
System.out.println("encryptedString: "+encryptedString);
String decyptedString = obj.decrypt(encryptedString, obj.encryptSecretKey(KEY));
System.out.println("decyptedString: "+decyptedString);
}
publicSecretKeySpecencryptSecretKey(finalStringsecretKey) {
MessageDigest sha =null;
SecretKeySpec encryptApiSecret =null;
try {
byte[] key = secretKey.getBytes("UTF-8");
sha =MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key =Arrays.copyOf(key, 16);
encryptApiSecret =newSecretKeySpec(key, "AES");
} catch (finalNoSuchAlgorithmException e) {
LOGGER.error("Exception occurred in encryptApiSecret",e);
} catch (finalUnsupportedEncodingException e) {
LOGGER.error("Exception occurred in encryptApiSecret",e);
}
return encryptApiSecret;
}
publicStringdecrypt(finalStringstrToDecrypt, finalSecretKeySpecsecretKey) {
String decryptedApiKey ="";
try {
finalCipher cipher =Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] c =Base64.decodeBase64(strToDecrypt.getBytes("UTF-8"));
decryptedApiKey =newString(cipher.doFinal(c));
} catch (finalException e) {
LOGGER.error("Exception occurred in decrypt",e);
}
return decryptedApiKey;
}
publicStringencrypt(finalStringstrToDecrypt, finalSecretKeySpecsecretKey) {
String encryptedApiKey ="";
try {
finalCipher cipher =Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] c = cipher.doFinal(strToDecrypt.getBytes());
encryptedApiKey =newString(Base64.encodeBase64(c));
} catch (finalException e) {
LOGGER.error("Exception occurred in encrypt",e);
}
return encryptedApiKey;
}
}
↧