Saturday 22 July 2017

Generic way to author text in AEM dialog

I am trying to author text in dialog, text contains dynamic values like name etc. I tried declaring sightly variable names in AEM dialog to fetch the data dynamically but it didn't work.



 I tried below approaches..

Approach 1:
/*
  * Using String format
  */
  String authoredText= "Hi %s, welcome to %s";
  authoredText = authoredText.format(authoredText,"Kishore","AEM Quickstart");
  log.info("---Using String format----\n"+authoredText);

Approach 2:
/*
  * Using StrSubstitutor - org.apache.commons.lang.text.StrSubstitutor
  */
  Map valuesMap = new HashMap();
  valuesMap.put("name", "Kishore");
  valuesMap.put("blog", "AEM Quickstart");
  String templateString = "Hi ${name}, welcome to ${blog}.";
  StrSubstitutor sub = new StrSubstitutor(valuesMap);
  String resolvedString = sub.replace(templateString);
  log.info("---Using StrSubstitutor----\n"+resolvedString);

Approach 3:
/**
   * Using String replace
   */
  String authoredText= "Hi ${name}, welcome to ${blog}";
  authoredText = authoredText.replace("${name}","Kishore");
  authoredText = authoredText.replace("${blog}","AEM Quickstart");
  log.info("---Using String replace----\n"+authoredText);

From above approaches we can author the text in any of the format and parse it in java and we can get the text in HTL.

org.osgi.framework.BundleException:osgi.wiring.package=com.adobe.cq.sightly

Sometimes when we try to deploy code, bundles may not be in active state in AEM 6.1. We can see below error message.

Error Message:
22.07.2017 10:40:27.509 *ERROR* [qtp2141213534-59] org.apache.felix.http.jetty %bundles.pluginTitle: Cannot start (org.osgi.framework.BundleException: Unresolved constraint in bundle com.aem.kishore.bundle-core [463]: Unable to resolve 463.2: missing requirement [463.2] osgi.wiring.package; (&(osgi.wiring.package=com.adobe.cq.sightly)(version>=2.2.0)(!(version>=3.0.0))))

org.osgi.framework.BundleException: Unresolved constraint in bundle com.aem.kishore.bundle-core[463]: Unable to resolve 463.2: missing requirement [463.2] osgi.wiring.package; (&(osgi.wiring.package=com.adobe.cq.sightly)(version>=2.2.0)(!(version>=3.0.0)))


Solution:
  • Delete existing bundle first.
  • Add below code in bundle pom.xml and rebuild the code.
<Import-Package>
    !org.apache.log.*,
    !org.apache.avalon.*
        -----------------------------
        -----------------------------
 </Import-Package>

Tuesday 18 July 2017

org.osgi.framework.BundleException: osgi.wiring.package=com.adobe.cq.mcm.salesforce

Sometimes when we try to deploy code, bundles may not be in active state in AEM 6.1. We can see below error message.

Error Message:
18.07.2017 23:44:01.519 *ERROR* [qtp1756110899-265] org.apache.felix.http.jetty %bundles.pluginTitle: Cannot start (org.osgi.framework.BundleException: Unresolved constraint in bundle com.aem.kishore.bundle-core [654]: Unable to resolve 654.1: missing requirement [654.1] osgi.wiring.package; (&(osgi.wiring.package=com.adobe.cq.mcm.salesforce)(version>=1.1.0)(!(version>=2.0.0))))
org.osgi.framework.BundleException: Unresolved constraint in bundle com.aem.kishore.bundle-core [654]: Unable to resolve 654.1: missing requirement [654.1] osgi.wiring.package; (&(osgi.wiring.package=com.adobe.cq.mcm.salesforce)(version>=1.1.0)(!(version>=2.0.0)))

Solution:
  • Delete (or stop) the ''org.eclipse.equinox.region" bundle from the felix.
  • Delete the existing custom bundle.
  • Restart the server (check without restarting) and then redeploy your code bundle.
This bundle has some dependency with eclipse and should not be in AEM6.1, it was meant for AEM 6.2. But somehow it got introduced in this version.

If still issue is not resolved check this post.

Tuesday 11 July 2017

java.lang.NoClassDefFoundError: com/day/cq/commons/Externalizer

I have developed a website using AEM 6.1 API. In some piece of java code I used the Externalizer class from AEM (com.day.cq.commons). This piece of code worked fine in 6.1 aem instance. When tried to deploy on AEM 6.2 got below error.


06.07.2017 09:55:54.242 *ERROR* [0:0:0:0:0:0:0:1 [1499331350444] GET /content/kishore/en/test.html HTTP/1.1] 
com.day.cq.wcm.core.impl.WCMDebugFilter Exception: com/day/cq/commons/Externalizer
java.lang.NoClassDefFoundError: com/day/cq/commons/Externalizer


Solution:

Fixed this issue by rebuilding the package with AEM 6.2 uber.jar

Offline Compaction - AEM Repository Size Growing Rapidly

Sometimes we observe AEM repository size increase rapidly. This post helps you in decreasing the respository size

AEM Repository Offline Compaction

  • Create new folder compact and place oak-run-1.2.2.jar and below .bat file.
  • Create a .bat file containing below code

java -jar oak-run-1.2.2.jar compact C:\Users\Kishore\AEM\crx-quickstart\repository\segmentstore

Download oak-run-1.2.2.jar

Tuesday 4 July 2017

Currency converter service

I am attaching simple program about, How to write Simple Currency Converter using Java Program. The program was written using Fixer Currency Converter Webservice. In this example, I am using Gson 2.8.0 API to convert JSON to Object in Java. you can download API from here.

CurrencyConversionResponse.java

package com.kishore.generic;

import java.util.Map;
import java.util.TreeMap;

public class CurrencyConversionResponse {

    private String base;
    private String date;

    private Map<String, String> rates = new TreeMap<String, String>();

    public Map<String, String> getRates() {
        return rates;
    }

    public void setRates(Map<String, String> rates) {
        this.rates = rates;
    }

    public String getBase() {
        return base;
    }

    public void setBase(String base) {
        this.base = base;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

}

CurrencyConvertor.java

package com.kishore.generic;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Scanner;

import com.google.gson.Gson;

public class CurrencyConvertor {

    // API Provider URL
    private static final String API_PROVDIER = "http://api.fixer.io/";

    public static double convert(String fromCurrencyCode, String toCurrencyCode) {

        if ((fromCurrencyCode != null && !fromCurrencyCode.isEmpty())
                && (toCurrencyCode != null && !toCurrencyCode.isEmpty())) {

            CurrencyConversionResponse response = getResponse(API_PROVDIER
                    + "/latest?base=" + fromCurrencyCode);

            if (response != null) {

                String rate = response.getRates().get(toCurrencyCode);

                double conversionRate = Double.valueOf((rate != null) ? rate: "0.0");

                return conversionRate;
            }

        }

        return 0.0;
    }

    // Method to get the response from API
    private static CurrencyConversionResponse getResponse(String strUrl) {

        CurrencyConversionResponse response = null;

        Gson gson = new Gson();
        StringBuffer sb = new StringBuffer();

        if (strUrl == null || strUrl.isEmpty()) {

            System.out.println("Application Error");
            return null;
        }

        URL url;
        try {
            url = new URL(strUrl);

            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();

            InputStream stream = connection.getInputStream();

            int data = stream.read();

            while (data != -1) {

                sb.append((char) data);

                data = stream.read();
            }

            stream.close();

            response = gson.fromJson(sb.toString(),
                    CurrencyConversionResponse.class);

        } catch (MalformedURLException e) {

            System.out.println(e.getMessage());
            e.printStackTrace();

        } catch (IOException e) {

            System.out.println(e.getMessage());
            e.printStackTrace();
        }

        return response;
    }

    public static void main(String[] args) throws IOException {

        Scanner scanner = new Scanner(System.in);

        System.out.println("What is your currency code ?");
        String fromCurrencyCode = scanner.next();

        System.out.println("Enter the Amount :");
        double amount = scanner.nextDouble();

        System.out
                .println("Enter the Currency Code that you want to covert : ");
        String toCurrencyCode = scanner.next();

        fromCurrencyCode = fromCurrencyCode.toUpperCase();
        toCurrencyCode = toCurrencyCode.toUpperCase();

        // Currency Conversion
        double coversionRate = convert(fromCurrencyCode, toCurrencyCode);

        System.out.println("Hi, The " + amount + " " + fromCurrencyCode
                + " is equivalent to " + (coversionRate * amount) + " "
                + toCurrencyCode + " today.");

        scanner.close();
    }

}

Output

What is your currency code ?
USD
Enter the Amount :
1
Enter the Currency Code that you want to covert : 
GBP
Hi, The 1.0 USD is equivalent to 0.77341 GBP today.



Monday 3 July 2017

Java code to format date

Sample code to format date
package com.kishore.samples;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 *
 * Java program to show how to format date in Java using SimpleDateFormat
 * Examples. Java allows to include date, time and timezone information
 * while formatting dates in Java.
 *
 */
public class DateFormatExample {

    public static void main(String args[]) {
      
        // This is how to get today's date in Java
        Date today = new Date();
      
        //If you print Date, you will get un formatted output
        System.out.println("Today is : " + today);
      
        //formatting date in Java using SimpleDateFormat
        SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy");
        String date = DATE_FORMAT.format(today);
        System.out.println("Today in dd-MM-yyyy format : " + date);
      
        //Another Example of formatting Date in Java using SimpleDateFormat
        DATE_FORMAT = new SimpleDateFormat("dd/MM/yy");
        date = DATE_FORMAT.format(today);
        System.out.println("Today in dd/MM/yy pattern : " + date);
      
        //formatting Date with time information
        DATE_FORMAT = new SimpleDateFormat("dd-MM-yy:HH:mm:SS");
        date = DATE_FORMAT.format(today);
        System.out.println("Today in dd-MM-yy:HH:mm:SS : " + date);
      
        //SimpleDateFormat example - Date with timezone information
        DATE_FORMAT = new SimpleDateFormat("dd-MM-yy:HH:mm:SS Z");
        date = DATE_FORMAT.format(today);
        System.out.println("Today in dd-MM-yy:HH:mm:SSZ : " + date);      
    }   
}

Output:

Today is : Mon Jul 03 23:16:17 IST 2017
Today in dd-MM-yyyy format : 03-07-2017
Today in dd/MM/yy pattern : 03/07/17
Today in dd-MM-yy:HH:mm:SS : 03-07-17:23:16:95
Today in dd-MM-yy:HH:mm:SSZ : 03-07-17:23:16:95 +0530

Format currency in Java

Sample code to format currency in java
package com.kishore.samples;

import java.text.NumberFormat;
import java.util.Locale;

/**
 * * How to format Number to different currency in Java. Following Java program
 * * will show you, how you can display double value in different currency e.g.
 * * USD, GBP and JPY. This example show price in multiple currency. 
 */
public class CurrencyFormater {
    public static void main(String args[]) {
        double price = 100.25;
        showPriceInUSD(price, getExchangeRate("USD"));
        showPriceInGBP(price, getExchangeRate("GBP"));
        showPriceInJPY(price, getExchangeRate("JPY"));
    }

    /** * Display price in US Dollar currency * * @param price * @param rate */
    public static void showPriceInUSD(double price, double rate) {
        double priceInUSD = price * rate;
        NumberFormat currencyFormat = NumberFormat
                .getCurrencyInstance(Locale.US);
        System.out.printf("Price in USD : %s %n",
                currencyFormat.format(priceInUSD));
    }

    /** * Display prince in British Pound * * @param price * @param rate */
    public static void showPriceInGBP(double price, double rate) {
        double princeInGBP = price * rate;
        NumberFormat GBP = NumberFormat.getCurrencyInstance(Locale.UK);
        System.out.printf("Price in GBP : %s %n", GBP.format(princeInGBP));
    }

    /** * Display prince in Japanese Yen * * @param price * @param rate */
    public static void showPriceInJPY(double price, double rate) {
        double princeInJPY = price * rate;
        NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.JAPAN);
        System.out.printf("Price in JPY : %s %n", currency.format(princeInJPY));
    }

    /** * @return FX exchange rate for USD * @param currency */
    public static double getExchangeRate(String currency) {
        switch (currency) {
        case "USD":
            return 1;
        case "JPY":
            return 102.53;
        case "GBP":
            return 0.60;
        case "EURO":
            return 0.73;
        default:
            throw new IllegalArgumentException(String.format(
                    "No rates available for currency %s %n", currency));
        }
    }
}

Output:

Price in USD : $100.25 
Price in GBP : £60.15 
Price in JPY : ?10,279 


Display number in different number patterns with locale

Sample code to display numbers in different pattern with locale like en_US
package com.kishore.samples;

import java.util.*;
import java.text.*;
 
public class DecimalFormatDemo {
 
   static public void customFormat(String pattern, double value ) {
      DecimalFormat myFormatter = new DecimalFormat(pattern);
      String output = myFormatter.format(value);
      System.out.println(value + " ===> " + pattern + " ===> " + output);
   }
 
   static public void localizedFormat(String pattern, double value, 
                                      Locale loc ) {
      NumberFormat nf = NumberFormat.getNumberInstance(loc);
      DecimalFormat df = (DecimalFormat)nf;
      df.applyPattern(pattern);
      String output = df.format(value);
      System.out.println(pattern + " ===> " + output + " ===> " + loc.toString());
   }
 
   static public void main(String[] args) {
       System.out.println("Number formats without Locale");
      customFormat("###,###.###", 123456.789);
      customFormat("###.##", 123456.789);
      customFormat("000000.000", 123.78);
      customFormat("$###,###.###", 12345.67);
      customFormat("\u00a5###,###.###", 12345.67);
 
      Locale currentLocale = new Locale("en", "US");
 
      DecimalFormatSymbols unusualSymbols = 
         new DecimalFormatSymbols(currentLocale);
      unusualSymbols.setDecimalSeparator('|');
      unusualSymbols.setGroupingSeparator('^');
      String strange = "#,##0.###";
      DecimalFormat weirdFormatter = new DecimalFormat(strange, unusualSymbols);
      weirdFormatter.setGroupingSize(4);
      String bizarre = weirdFormatter.format(12345.678);
      System.out.println(bizarre);
 
      Locale[] locales = {
         new Locale("en", "US"),
         new Locale("de", "DE"),
         new Locale("fr", "FR")
      };
      System.out.println("Number formats with Locale");
      for (int i = 0; i < locales.length; i++) {
         localizedFormat("###,###.###", 123456.789, locales[i]);
      }
 
   }
}

Output:

Number formats without Locale
123456.789 ===> ###,###.### ===> 123,456.789
123456.789 ===> ###.## ===> 123456.79
123.78 ===> 000000.000 ===> 000123.780
12345.67 ===> $###,###.### ===> $12,345.67
12345.67 ===> ¥###,###.### ===> ¥12,345.67
1^2345|678
Number formats with Locale
###,###.### ===> 123,456.789 ===> en_US
###,###.### ===> 123.456,789 ===> de_DE
###,###.### ===> 123 456,789 ===> fr_FR

Reference:
https://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html

Display number in different number patterns

You can use the java.text.DecimalFormat class to control the display of leading and trailing zeros, prefixes and suffixes, grouping (thousands) separators, and the decimal separator. DecimalFormat offers a great deal of flexibility in the formatting of numbers, but it can make your code more complex.
The example that follows creates a DecimalFormat object, myFormatter, by passing a pattern string to the DecimalFormat constructor. The format() method, which DecimalFormat inherits from NumberFormat, is then invoked by myFormatter—it accepts a double value as an argument and returns the formatted number in a string:
Here is a sample program that illustrates the use of DecimalFormat:
import java.text.*;

public class DecimalFormatDemo {

   static public void customFormat(String pattern, double value ) {
      DecimalFormat myFormatter = new DecimalFormat(pattern);
      String output = myFormatter.format(value);
      System.out.println(value + " ===> " + pattern + " ===> " + output);
   }

   static public void main(String[] args) {

      customFormat("###,###.###", 123456.789);
      customFormat("###.##", 123456.789);
      customFormat("000000.000", 123.78);
      customFormat("$###,###.###", 12345.67);  
   }
}

The output is:
123456.789 ===> ###,###.### ===> 123,456.789
123456.789 ===> ###.## ===> 123456.79
123.78 ===> 000000.000 ===> 000123.780
12345.67 ===> $###,###.### ===> $12,345.67

Reference:

Not able to inherit page properties from parent page

Problem:
I have created a live copy from Geometrixx site. I have pointed cq:template and sling:resourceType of parent page to my custom template and page component. I have created a new child page, when I checked the page properties of child page I don't see inheritance (lock symbol) on my child page properties dialog.

-Sample/
     -en/
          -childpage/

Solution:
I am able to see the lock symbol on child page properties dialog after adding the mixin "cq:LiveRelationship".

Saturday 1 July 2017

AEM Page Properties Touch UI Dialog conversion issue

When tried to create a touch dialog of page properties from classic ui we may may get duplicate widgets on the newly created touch dialog from dialog conversion tool. See how to create touch dialog from dialog conversion tool.

To avoid above issue you can use granite/ui/components/foundation/include resource type in the touch ui for including granite UI components in the current component dialogs. Take a look at the following example in crxde - /libs/wcm/foundation/components/page/cq:dialog/content/items/tabs/items/basic

Failed to execute goal org.apache.felix:maven-scr-plugin

Issue:
I have created maven archetype 10 project for AEM 6.1 and jdk 1.8. When I ran mvn clean install I ran in to below errors.

1) When maven-scr-plugin (1.11.0) and org.apache.felix.scr.annotations (1.9.0)
[ERROR] Failed to execute goal org.apache.felix:maven-scr-plugin:1.11.0:scr (generate-scr-descriptor) on project digital-spearhead-core: Execution generate-scr-descriptor of goal org.apache.felix:maven-scr-plugin:1.11.0:scr failed. IllegalArgumentException -> [Help 1]

2) When maven-scr-plugin (1.12.0) and org.apache.felix.scr.annotations (1.9.0)
[ERROR] Failed to execute goal org.apache.felix:maven-scr-plugin:1.12.0:scr (generate-scr-descriptor) on project aem-sample-core: SCR Descriptor parsing had failures (see log) -> [Help 1]

Solution:
Use correct maven-scr-plugin and org.apache.felix.scr.annotations versions.  I have used maven-scr-plugin (1.20.0) and org.apache.felix.scr.annotations (1.9.0), now build is success.