Uploaded image for project: 'SMB - Optus'
  1. SMB - Optus
  2. OPTUS-110

Regex Issue in DOMPersistanceManager.java in Core Project causing site generation failure.

    Details

      Description

      We’ve come across a site deployment error In production in which a site is attempting to use the following sentence as content:
      “QWEST then help you then choose the builder best suited to the project all for no cost to you! (*conditions apply contact QWEST for details)”

      When we deploy the site, we receive the error:

      2013-02-25 15:22:18,586 DEBUG [org.springframework.jdbc.core.JdbcTemplate] (WorkManager(2)-86) Executing SQL batch update [UPDATE customerField SET value = ? , customized = ? WHERE customizable_entity_id = ? AND id = ? ]
      2013-02-25 15:22:18,586 DEBUG [org.springframework.jdbc.core.JdbcTemplate] (WorkManager(2)-86) Executing prepared SQL statement [UPDATE customerField SET value = ? , customized = ? WHERE customizable_entity_id = ? AND id = ? ]
      2013-02-25 15:22:18,588 ERROR [com.thesearchagency.smb.service.site.component.SiteServiceBD] (WorkManager(2)-86) Process during context processing step : class com.thesearchagency.smb.service.site.component.contextprocessing.customizatio
      n.CustomerSiteExporterCP
      java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 136
      5,QWEST\s*then\s*help\s*you\s*then\s*choose\s*the\s*builder\s*best\s*suited\s*to\s*the\s*project\s*all\s*for\s*no\s*cost\s*to\s*you!\s*(*conditions\s*apply\s*contact\s*QWEST\s*for\s*details)
      ^
      at java.util.regex.Pattern.error(Pattern.java:1713)
      at java.util.regex.Pattern.sequence(Pattern.java:1878)
      at java.util.regex.Pattern.expr(Pattern.java:1752)
      at java.util.regex.Pattern.group0(Pattern.java:2530)
      at java.util.regex.Pattern.sequence(Pattern.java:1806)
      at java.util.regex.Pattern.expr(Pattern.java:1752)
      at java.util.regex.Pattern.compile(Pattern.java:1460)
      at java.util.regex.Pattern.<init>(Pattern.java:1133)
      at java.util.regex.Pattern.compile(Pattern.java:823)
      at com.thesearchagency.core.smb.dao.contentmodel.DOMPersistanceManager.syncFields(DOMPersistanceManager.java:185)
      at com.thesearchagency.core.smb.dao.contentmodel.DOMPersistanceManager.updateContentFields(DOMPersistanceManager.java:209)
      at com.thesearchagency.core.smb.dao.contentmodel.DOMPersistanceManager.updateContentModelBranch(DOMPersistanceManager.java:155)
      at com.thesearchagency.core.smb.dao.contentmodel.DOMPersistanceManager.syncChildren(DOMPersistanceManager.java:250)
      at com.thesearchagency.core.smb.dao.contentmodel.DOMPersistanceManager.updateContentModelBranch(DOMPersistanceManager.java:157)
      at com.thesearchagency.core.smb.dao.contentmodel.DOMPersistanceManager.syncChildren(DOMPersistanceManager.java:250)
      at com.thesearchagency.core.smb.dao.contentmodel.DOMPersistanceManager.updateContentModelBranch(DOMPersistanceManager.java:157)
      at sun.reflect.GeneratedMethodAccessor648.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:196)
      at $Proxy1122.updateContentModelBranch(Unknown Source)
      at com.thesearchagency.core.smb.service.content_model.component.CustomerSiteServiceBD.update(CustomerSiteServiceBD.java:90)
      at com.thesearchagency.core.smb.service.content_model.component.CustomerSiteServiceBD.updateWithoutCallback(CustomerSiteServiceBD.java:81)
      at sun.reflect.GeneratedMethodAccessor662.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

      The ^ arrow may be pointing to a different place, depending on font size, but it is supposed to be targeting the highlighted ‘*’ in “(*conditions\s*apply\s*contact\s*QWEST\s*for\s*details)”
      I’ve followed through the process and eventually arrived at the class: DOMPersistanceManager.java. It is located at core / backend / services / core-common-parent / dao / src / main / java / com / thesearchagency / core / smb / dao / contentmodel / DOMPersistanceManager.java in the core project. The function in particular is “syncFields”. This is what it looked like initially, with email comments in green:

      private <T extends CustomerField, DAO extends IFieldDAO<T>> void syncFields(ArrayList<T> current, ArrayList<T> updated, Boolean isCustomization, DAO aDAO){
      // sync any CustomerFields that are in both
      ArrayList<T> updatedFields = new ArrayList<T>();
      for(T updatedField : updated){
      if(updatedField!=null){
      T currentField = getSameField(updatedField, current);
      if(currentField != null){
      if( updatedField.getValue()==null)

      { currentField.setValue(""); if(isCustomization) currentField.setCustomized(isCustomization); }else{
      //It seems as if the function does try to delimit a few of the regex special characters, but a few still crept by.
      //In particular, the * and + characters if placed after a special character will cause an error [e.g. “(*” from before]
      String currentText = currentField.getValue().replaceAll(" ", "\\\\s*");
      String updatedText = updatedField.getValue();
      currentText = currentText.replaceAll("
      {", "\\\\{");
      // Sometimes bad content gets in with square brackets in replacement tags.
      // Granted this should be fixed in content loading, but we cannot assume that at this point.
      currentText = currentText.replaceAll("
      [", "\\\\[");
      updatedText = updatedText.replaceAll("
      [", "\\\\[");

      currentText = currentText.replaceAll("GEO
      d*", "GEO");
      updatedText = updatedText.replaceAll("GEO
      d*", "GEO");

      Pattern pat = Pattern.compile(currentText);
      if (!pat.matcher(updatedText).matches()){ currentField.setValue(updatedField.getValue()); if(isCustomization) currentField.setCustomized(isCustomization); }
      }
      }
      if(currentField!=null) updatedFields.add(currentField);
      }
      }
      if(updatedFields.size()>0) aDAO.update(updatedFields);

      }

      Thus, I’m suggesting this change, which will treat the initial text as a literal string (so regex doesn’t misread it accidentally, but still allow spaces to be variable in size/number. Additions in yellow, removals in red.


      private <T extends CustomerField, DAO extends IFieldDAO<T>> void syncFields(ArrayList<T> current, ArrayList<T> updated, Boolean isCustomization, DAO aDAO){
      // sync any CustomerFields that are in both
      ArrayList<T> updatedFields = new ArrayList<T>();
      for(T updatedField : updated){
      if(updatedField!=null){
      T currentField = getSameField(updatedField, current);
      if(currentField != null){
      if( updatedField.getValue()==null){ currentField.setValue(""); if(isCustomization) currentField.setCustomized(isCustomization); }

      else{
      String currentText = currentField.getValue().replaceAll(" ", "\\\\s*");
      // Sometimes content has special characters that cause regex errors.
      // Pattern.quote suppresses the meaning of special characters.
      String currentText = Pattern.quote(currentField.getValue());
      //Exit and re-enter literal quoting to allow for differences in spacing during regex.
      currentText = currentText.replaceAll(" ", "\\\\E\\\\s*\\\\Q");
      String updatedText = updatedField.getValue();
      currentText = currentText.replaceAll("
      {", "\\\\{");
      currentText = currentText.replaceAll("
      [", "\\\\[");
      updatedText = updatedText.replaceAll("
      [", "\\\\[");

      currentText = currentText.replaceAll("GEO
      d*", "GEO");
      updatedText = updatedText.replaceAll("GEO
      d*", "GEO");

      Pattern pat = Pattern.compile(currentText);
      if (!pat.matcher(updatedText).matches())

      { currentField.setValue(updatedField.getValue()); if(isCustomization) currentField.setCustomized(isCustomization); }


      }
      }
      if(currentField!=null) updatedFields.add(currentField);
      }
      }
      if(updatedFields.size()>0) aDAO.update(updatedFields);

      }

      I performed some regex testing using a small separate standalone java class, to double check the constraints on the matching is still correct: Regex2.java
      import java.util.regex.*;

      public class RegexTest2 {
      public static void main(String[] args) throws Exception
      {
      try
      {
      String currentField = "5,QWEST then help you then choose the builder best suited to the project all for no cost to you! GEO10 (*conditions apply contact QWEST for details)";
      String aText = "5,QWEST then help you then choose the builder best suited to the project all for no cost to you! GEO10 (*conditions apply contact QWEST for details)";
      String currentText2= Pattern.quote(currentField);
      currentText2 = currentText2.replaceAll(" ", "\\\\E\\\\s*\\\\Q");
      currentText2 = currentText2.replaceAll("GEO
      d*", "GEO");
      aText = aText.replaceAll("GEO
      d*", "GEO");
      Pattern pat = Pattern.compile(currentText2);
      if (pat.matcher(aText).matches())

      { System.out.println(currentText2); System.out.println(aText); }

      }
      catch(Exception e)

      { System.err.println(e); }

      }
      }
      Which prints out:
      \Q5,QWEST\E\s*\Qthen\E\s*\Qhelp\E\s*\Qyou\E\s*\Qthen\E\s*\Qchoose\E\s*\Qthe\E\s*\Qbuilder\E\s*\Qbest\E\s*\Qsuited\E\s*\Qto\E\s*\Qthe\E\s*\Qproject\E\s*\Qall\E\s*\Qfor\E\s*\Qno\E\s*\Qcost\E\s*\Qto\E\s*\Qyou!\E\s*\QGEO\E\s*\Q(conditions\E\s\Qapply\E\s*\Qcontact\E\s*\QQWEST\E\s*\Qfor\E\s*\Qdetails)\E
      5,QWEST then help you then choose the builder best suited to the project all for no cost to you! GEO (*conditions apply contact QWEST for details)

      Showing that the matching still works, and that the \s* and GEO replacements and regexes are still executed correctly during the regex. I also played around with the input texts to check how it worked with other special characters, and if differences worked as expected.

      After making sure this regex conversion worked, I updated the DOMPersistanceManager in my local build (as above), compiled it, and tested it on PPT, using the PPT SSUI test site “http://www.oda6.prep.optusnet.com.au” to test the change. I updated the content of the florists page to read “QWEST then help you then choose the builder best suited to the project all for no cost to you! (*conditions apply contact QWEST for details)” in the first paragraph’s first sentence. The site redeployed with no errors, suggesting the change worked.

      I've also attached the updated file to this issue.

        Attachments

          Activity

            People

            • Assignee:
              manasa.denning Manasa Denning
              Reporter:
              paul.swe Paul Swe (Inactive)
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Time Tracking

                Estimated:
                Original Estimate - 2 hours
                2h
                Remaining:
                Remaining Estimate - 2 hours
                2h
                Logged:
                Time Spent - Not Specified
                Not Specified