Coverage Report - org.kuali.maven.mojo.s3.UpdateOriginBucketMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
UpdateOriginBucketMojo
0%
0/197
0%
0/52
1.867
 
 1  
 package org.kuali.maven.mojo.s3;
 2  
 
 3  
 import java.io.ByteArrayInputStream;
 4  
 import java.io.IOException;
 5  
 import java.io.InputStream;
 6  
 import java.text.SimpleDateFormat;
 7  
 import java.util.Collection;
 8  
 import java.util.Date;
 9  
 import java.util.List;
 10  
 import java.util.Map;
 11  
 import java.util.TimeZone;
 12  
 
 13  
 import org.apache.commons.beanutils.BeanUtils;
 14  
 import org.apache.commons.io.IOUtils;
 15  
 import org.apache.commons.lang.StringUtils;
 16  
 import org.apache.maven.plugin.MojoExecutionException;
 17  
 import org.apache.maven.plugin.MojoFailureException;
 18  
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 19  
 import org.apache.maven.project.MavenProject;
 20  
 import org.kuali.maven.common.UrlBuilder;
 21  
 
 22  
 import com.amazonaws.auth.AWSCredentials;
 23  
 import com.amazonaws.services.s3.AmazonS3Client;
 24  
 import com.amazonaws.services.s3.model.CannedAccessControlList;
 25  
 import com.amazonaws.services.s3.model.CopyObjectRequest;
 26  
 import com.amazonaws.services.s3.model.ListObjectsRequest;
 27  
 import com.amazonaws.services.s3.model.ObjectListing;
 28  
 import com.amazonaws.services.s3.model.ObjectMetadata;
 29  
 import com.amazonaws.services.s3.model.PutObjectRequest;
 30  
 import com.amazonaws.services.s3.model.S3Object;
 31  
 import com.amazonaws.services.s3.model.S3ObjectSummary;
 32  
 
 33  
 /**
 34  
  * <p>
 35  
  * This mojo updates a bucket serving as an origin for a Cloud Front distribution. It generates an html directory
 36  
  * listing for each "directory" in the bucket and stores the html under a key in the bucket such that a regular http
 37  
  * request for a directory returns the html instead of the XML for "object does not exist" Amazon would normally return.
 38  
  * For example: The url "http://www.mybucket.com/foo/bar" returns an html page containing a listing of all the files and
 39  
  * directories under "foo/bar" in the bucket.
 40  
  * </p>
 41  
  * <p>
 42  
  * If a directory contains an object with a key that is the same as the default object, the plugin copies the object to
 43  
  * a key representing the directory structure. For example, the url "http://www.mybucket.com/foo/bar/index.html"
 44  
  * represents an object in an S3 bucket under the key "foo/bar/index.html". This plugin will copy the object from the
 45  
  * key "foo/bar/index.html" to the key "foo/bar/". This causes the url "http://www.mybucket.com/foo/bar/" to return the
 46  
  * same content as the url "http://www.mybucket.com/foo/bar/index.html"
 47  
  * </p>
 48  
  * <p>
 49  
  * It also generates an html directory listing at the root of the bucket hierarchy and places that html into the bucket
 50  
  * as the default object, unless a default object already exists.
 51  
  * </p>
 52  
  * 
 53  
  * @goal updateoriginbucket
 54  
  */
 55  0
 public class UpdateOriginBucketMojo extends S3Mojo {
 56  
 
 57  
         private static final String S3_INDEX_METADATA_KEY = "maven-cloudfront-plugin-index";
 58  
         private static final String S3_INDEX_CONTENT_TYPE = "text/html";
 59  
         CloudFrontHtmlGenerator generator;
 60  
         S3DataConverter converter;
 61  
 
 62  
         /**
 63  
          * The groupId for the organization
 64  
          * 
 65  
          * @parameter expression="${organizationGroupId}" default-value="org.kuali"
 66  
          */
 67  
         private String organizationGroupId;
 68  
 
 69  
         /**
 70  
          * This controls the caching behavior for CloudFront. By default, CloudFront edge locations cache content from an S3
 71  
          * bucket for 24 hours. That interval is shortened to 1 hour for the html indexes generated by this plugin.
 72  
          * 
 73  
          * @parameter expression="${cacheControl}" default-value="max-age=3600, must-revalidate"
 74  
          */
 75  
         private String cacheControl;
 76  
 
 77  
         /**
 78  
          * If true, the complete hierarchy underneath <code>prefix</code> will be recursively updated. If false, only the
 79  
          * directory corresponding to the prefix will be updated along with the path back to the root of the bucket
 80  
          * 
 81  
          * @parameter expression="${recurse}" default-value="true"
 82  
          */
 83  
         private boolean recurse;
 84  
 
 85  
         /**
 86  
          * @parameter expression="${updateChildModules}" default-value="false"
 87  
          */
 88  
         private boolean updateChildModules;
 89  
 
 90  
         /**
 91  
          * If true, "foo/bar/index.html" will get copied to "foo/bar/"
 92  
          * 
 93  
          * @parameter expression="${copyDefaultObjectWithDelimiter}" default-value="true"
 94  
          */
 95  
         private boolean copyDefaultObjectWithDelimiter;
 96  
 
 97  
         /**
 98  
          * If true, "foo/bar/index.html" will get copied to "foo/bar". This is defaulted to false because the relative
 99  
          * pathing in the html generated by the maven-site-plugin does not render correctly from a url without the trailing
 100  
          * slash.
 101  
          * 
 102  
          * @parameter expression="${copyDefaultObjectWithoutDelimiter}" default-value="false"
 103  
          */
 104  
         private boolean copyDefaultObjectWithoutDelimiter;
 105  
 
 106  
         /**
 107  
          * The stylesheet to use for the directory listing
 108  
          * 
 109  
          * @parameter expression="${css}" default-value="http://s3browse.ks.kuali.org/css/style.css"
 110  
          */
 111  
         private String css;
 112  
 
 113  
         /**
 114  
          * Image representing a file
 115  
          * 
 116  
          * @parameter expression="${fileImage}" default-value="http://s3browse.ks.kuali.org/images/page_white.png"
 117  
          */
 118  
         private String fileImage;
 119  
 
 120  
         /**
 121  
          * Image representing a directory
 122  
          * 
 123  
          * @parameter expression="${directoryImage}" default-value="http://s3browse.ks.kuali.org/images/folder.png"
 124  
          */
 125  
         private String directoryImage;
 126  
 
 127  
         /**
 128  
          * When displaying the last modified timestamp, use this timezone
 129  
          * 
 130  
          * @parameter expression="${timezone}" default-value="GMT"
 131  
          */
 132  
         private String timezone;
 133  
 
 134  
         /**
 135  
          * When displaying the last modified timestamp use this format
 136  
          * 
 137  
          * @parameter expression="${dateFormat}" default-value="EEE, dd MMM yyyy HH:mm:ss z"
 138  
          */
 139  
         private String dateFormat;
 140  
 
 141  
         /**
 142  
          * The key containing the default object for the Cloud Front distribution. If this object already exists, the plugin
 143  
          * will not modify it. If it does not exist, this plugin will generate an html directory listing and place it into
 144  
          * the bucket under this key.
 145  
          * 
 146  
          * @parameter expression="${defaultObject}" default-value="index.html";
 147  
          */
 148  
         private String defaultObject;
 149  
 
 150  
         /**
 151  
          * The html for browsing a directory will be created under this key
 152  
          * 
 153  
          * @parameter expression="${browseHtml}" default-value="browse.html";
 154  
          */
 155  
         private String browseHtml;
 156  
 
 157  
         @Override
 158  
         public void executeMojo() throws MojoExecutionException, MojoFailureException {
 159  
                 try {
 160  0
                         getLog().info("Updating S3 bucket - " + getBucket());
 161  0
                         S3BucketContext context = getS3BucketContext();
 162  0
                         generator = new CloudFrontHtmlGenerator(context);
 163  0
                         converter = new S3DataConverter(context);
 164  0
                         converter.setBrowseHtml(getBrowseHtml());
 165  0
                         if (isRecurse()) {
 166  0
                                 getLog().info("Recursing into " + getPrefix());
 167  0
                                 recurse(context, getPrefix());
 168  
                         }
 169  0
                         getLog().info("Updating hierarchy above " + getPrefix());
 170  0
                         goUpTheChain(context, getPrefix());
 171  0
                 } catch (Exception e) {
 172  0
                         throw new MojoExecutionException("Unexpected error: ", e);
 173  0
                 }
 174  0
         }
 175  
 
 176  
         protected void goUpTheChain(final S3BucketContext context, final String startingPrefix) throws IOException {
 177  0
                 handleRoot(getS3PrefixContext(context, null));
 178  
 
 179  0
                 if (StringUtils.isEmpty(startingPrefix)) {
 180  0
                         return;
 181  
                 }
 182  
 
 183  0
                 String[] prefixes = StringUtils.splitByWholeSeparator(startingPrefix, context.getDelimiter());
 184  0
                 if (prefixes.length == 1) {
 185  0
                         return;
 186  
                 }
 187  0
                 String newPrefix = "";
 188  0
                 for (int i = 0; i < prefixes.length - 2; i++) {
 189  0
                         newPrefix += prefixes[i] + context.getDelimiter();
 190  0
                         updateDirectory(getS3PrefixContext(context, newPrefix));
 191  
                 }
 192  0
         }
 193  
 
 194  
         protected String getDefaultPrefix(MavenProject project, String groupId) {
 195  0
                 UrlBuilder builder = new UrlBuilder();
 196  
 
 197  0
                 if (builder.isBaseCase(project, groupId)) {
 198  0
                         return builder.getSitePath(project, groupId) + "/" + project.getVersion();
 199  
                 } else {
 200  0
                         return getDefaultPrefix(project.getParent(), groupId) + "/" + project.getArtifactId();
 201  
                 }
 202  
         }
 203  
 
 204  
         protected void updatePrefix() {
 205  0
                 String s = getPrefix();
 206  0
                 if (StringUtils.isEmpty(s)) {
 207  0
                         s = getDefaultPrefix(getProject(), getOrganizationGroupId());
 208  
                 }
 209  0
                 if (!s.endsWith(getDelimiter())) {
 210  0
                         s = s + getDelimiter();
 211  
                 }
 212  0
                 setPrefix(s);
 213  0
         }
 214  
 
 215  
         protected S3BucketContext getS3BucketContext() throws MojoExecutionException {
 216  0
                 updateCredentials();
 217  0
                 validateCredentials();
 218  0
                 AWSCredentials credentials = getCredentials();
 219  0
                 AmazonS3Client client = new AmazonS3Client(credentials);
 220  0
                 updatePrefix();
 221  0
                 S3BucketContext context = new S3BucketContext();
 222  
                 try {
 223  0
                         BeanUtils.copyProperties(context, this);
 224  0
                 } catch (Exception e) {
 225  0
                         throw new MojoExecutionException("Error copying properties", e);
 226  0
                 }
 227  0
                 context.setClient(client);
 228  0
                 context.setLastModifiedDateFormatter(getLastModifiedDateFormatter());
 229  0
                 context.setAbout(getAbout());
 230  0
                 return context;
 231  
         }
 232  
 
 233  
         /**
 234  
          * Create a PutObjectRequest for some html generated by this mojo. The PutObjectRequest sets the content type to
 235  
          * S3_INDEX_CONTENT_TYPE, sets the ACL to PublicRead, and adds some custom metadata so we can positively identify it
 236  
          * as an object created by this plugin
 237  
          */
 238  
         protected PutObjectRequest getPutIndexObjectRequest(final String html, final String key) throws IOException {
 239  0
                 InputStream in = new ByteArrayInputStream(html.getBytes());
 240  0
                 ObjectMetadata om = new ObjectMetadata();
 241  0
                 om.setCacheControl(getCacheControl());
 242  0
                 String contentType = S3_INDEX_CONTENT_TYPE;
 243  0
                 om.setContentType(contentType);
 244  0
                 om.setContentLength(html.length());
 245  0
                 om.addUserMetadata(S3_INDEX_METADATA_KEY, "true");
 246  0
                 PutObjectRequest request = new PutObjectRequest(getBucket(), key, in, om);
 247  0
                 request.setCannedAcl(CannedAccessControlList.PublicRead);
 248  0
                 return request;
 249  
         }
 250  
 
 251  
         /**
 252  
          * Return a SimpleDateFormat object initialized with the date format and timezone supplied to the mojo
 253  
          */
 254  
         protected SimpleDateFormat getLastModifiedDateFormatter() {
 255  0
                 SimpleDateFormat sdf = new SimpleDateFormat(getDateFormat());
 256  0
                 sdf.setTimeZone(TimeZone.getTimeZone(getTimezone()));
 257  0
                 return sdf;
 258  
         }
 259  
 
 260  
         /**
 261  
          * Return true if the Collection is null or contains no entries, false otherwise
 262  
          */
 263  
         protected boolean isEmpty(final Collection<?> c) {
 264  0
                 return c == null || c.size() == 0;
 265  
         }
 266  
 
 267  
         /**
 268  
          * Show some text about this plugin
 269  
          */
 270  
         protected String getAbout() {
 271  0
                 String date = getLastModifiedDateFormatter().format(new Date());
 272  0
                 PluginDescriptor descriptor = (PluginDescriptor) this.getPluginContext().get("pluginDescriptor");
 273  0
                 if (descriptor == null) {
 274  
                         // Maven 2.2.1 is returning a null descriptor
 275  0
                         return "Listing generated by the maven-cloudfront-plugin on " + date;
 276  
                 } else {
 277  0
                         String name = descriptor.getArtifactId();
 278  0
                         String version = descriptor.getVersion();
 279  0
                         return "Listing generated by the " + name + " v" + version + " on " + date;
 280  
                 }
 281  
         }
 282  
 
 283  
         /**
 284  
          * Create an object in the bucket under a key that lets a normal http request function correctly with CloudFront /
 285  
          * S3.<br>
 286  
          * Either use the client's object or upload some html created by this plugin<br>
 287  
          */
 288  
         protected void updateDirectory(final S3PrefixContext context, final boolean isCopyIfExists, final String copyToKey)
 289  
                         throws IOException {
 290  0
                 S3BucketContext bucketContext = context.getBucketContext();
 291  0
                 AmazonS3Client client = context.getBucketContext().getClient();
 292  0
                 String bucket = bucketContext.getBucket();
 293  
 
 294  0
                 boolean containsDefaultObject = isExistingObject(context.getObjectListing(), context.getDefaultObjectKey());
 295  0
                 if (containsDefaultObject && isCopyIfExists) {
 296  
                         // Copy the contents of the clients default object
 297  0
                         String sourceKey = context.getDefaultObjectKey();
 298  0
                         String destKey = copyToKey;
 299  0
                         CopyObjectRequest request = getCopyObjectRequest(bucket, sourceKey, destKey);
 300  0
                         getLog().info("Copy: " + sourceKey + " to " + destKey);
 301  0
                         client.copyObject(request);
 302  0
                 } else {
 303  
                         // Upload our custom content
 304  0
                         PutObjectRequest request = getPutIndexObjectRequest(context.getHtml(), copyToKey);
 305  0
                         getLog().info("Put: " + copyToKey);
 306  0
                         client.putObject(request);
 307  
                 }
 308  0
         }
 309  
 
 310  
         /**
 311  
          * Update this S3 "directory".
 312  
          */
 313  
         protected void updateDirectory(final S3PrefixContext context) throws IOException {
 314  0
                 String trimmedPrefix = converter.getTrimmedPrefix(context.getPrefix(), context.getBucketContext()
 315  
                                 .getDelimiter());
 316  
 
 317  
                 // Handle "http://www.mybucket.com/foo/bar/"
 318  0
                 updateDirectory(context, isCopyDefaultObjectWithDelimiter(), context.getPrefix());
 319  
 
 320  
                 // Handle "http://www.mybucket.com/foo/bar"
 321  0
                 updateDirectory(context, isCopyDefaultObjectWithoutDelimiter(), trimmedPrefix);
 322  
 
 323  
                 // Handle "http://www.mybucket.com/foo/bar/browse.html"
 324  
                 // context.getBucketContext().getClient().putObject(getPutIndexObjectRequest(context.getHtml(),
 325  
                 // context.getBrowseHtmlKey()));
 326  0
         }
 327  
 
 328  
         /**
 329  
          * If this is the root of the bucket and the default object either does not exist or was created by this plugin,
 330  
          * overwrite the default object with newly generated html. Otherwise, do nothing.
 331  
          */
 332  
         protected void handleRoot(final S3PrefixContext context) throws IOException {
 333  0
                 if (!context.isRoot()) {
 334  0
                         return;
 335  
                 }
 336  
 
 337  0
                 AmazonS3Client client = context.getBucketContext().getClient();
 338  
 
 339  
                 // Handle "http://www.mybucket.com/browse.html"
 340  0
                 PutObjectRequest request1 = getPutIndexObjectRequest(context.getHtml(), context.getBrowseHtmlKey());
 341  0
                 getLog().info("Put: " + context.getBrowseHtmlKey());
 342  0
                 client.putObject(request1);
 343  
 
 344  0
                 boolean isCreateOrUpdateDefaultObject = isCreateOrUpdateDefaultObject(context);
 345  0
                 if (!isCreateOrUpdateDefaultObject) {
 346  0
                         return;
 347  
                 }
 348  
 
 349  
                 // Update the default object
 350  0
                 PutObjectRequest request2 = getPutIndexObjectRequest(context.getHtml(), context.getDefaultObjectKey());
 351  0
                 getLog().info("Put: " + context.getDefaultObjectKey());
 352  0
                 client.putObject(request2);
 353  0
         }
 354  
 
 355  
         protected S3PrefixContext getS3PrefixContext(final S3BucketContext context, final String prefix) {
 356  0
                 ListObjectsRequest request = new ListObjectsRequest(context.getBucket(), prefix, null, context.getDelimiter(),
 357  
                                 1000);
 358  0
                 ObjectListing objectListing = context.getClient().listObjects(request);
 359  0
                 List<String[]> data = converter.getData(objectListing, prefix, context.getDelimiter());
 360  0
                 String html = generator.getHtml(data, prefix, context.getDelimiter());
 361  0
                 String defaultObjectKey = StringUtils.isEmpty(prefix) ? getDefaultObject() : prefix + getDefaultObject();
 362  0
                 String browseHtmlKey = StringUtils.isEmpty(prefix) ? getBrowseHtml() : prefix + getBrowseHtml();
 363  
                 // Is this the root of the bucket?
 364  0
                 boolean isRoot = StringUtils.isEmpty(prefix);
 365  
 
 366  0
                 S3PrefixContext prefixContext = new S3PrefixContext();
 367  0
                 prefixContext.setObjectListing(objectListing);
 368  0
                 prefixContext.setHtml(html);
 369  0
                 prefixContext.setRoot(isRoot);
 370  0
                 prefixContext.setDefaultObjectKey(defaultObjectKey);
 371  0
                 prefixContext.setPrefix(prefix);
 372  0
                 prefixContext.setBucketContext(context);
 373  0
                 prefixContext.setBrowseHtmlKey(browseHtmlKey);
 374  0
                 return prefixContext;
 375  
         }
 376  
 
 377  
         /**
 378  
          * Recurse the hierarchy of a bucket starting at "prefix" and create entries in the bucket corresponding to the
 379  
          * directory structure of the hierarchy
 380  
          */
 381  
         protected void recurse(final S3BucketContext context, final String prefix) throws IOException {
 382  0
                 S3PrefixContext prefixContext = getS3PrefixContext(context, prefix);
 383  
 
 384  0
                 handleRoot(prefixContext);
 385  
 
 386  
                 // If this is not the root, there is more to do
 387  0
                 if (!prefixContext.isRoot()) {
 388  0
                         updateDirectory(prefixContext);
 389  
                 }
 390  
 
 391  
                 // Recurse down the hierarchy
 392  0
                 List<String> commonPrefixes = prefixContext.getObjectListing().getCommonPrefixes();
 393  0
                 for (String commonPrefix : commonPrefixes) {
 394  0
                         if (isChildModule(commonPrefix) && !isUpdateChildModules()) {
 395  0
                                 getLog().info("Skipping " + commonPrefix);
 396  0
                                 continue;
 397  
                         } else {
 398  0
                                 recurse(context, commonPrefix);
 399  
                         }
 400  
                 }
 401  0
         }
 402  
 
 403  
         protected boolean isChildModule(String commonPrefix) {
 404  0
                 List<String> modules = getProject().getModules();
 405  0
                 for (String module : modules) {
 406  0
                         if (commonPrefix.endsWith(module + "/")) {
 407  0
                                 return true;
 408  
                         }
 409  
                 }
 410  0
                 return false;
 411  
         }
 412  
 
 413  
         /**
 414  
          * Return true if the ObjectListing contains an object under "key"
 415  
          */
 416  
         protected boolean isExistingObject(final ObjectListing objectListing, final String key) {
 417  0
                 List<S3ObjectSummary> summaries = objectListing.getObjectSummaries();
 418  0
                 for (S3ObjectSummary summary : summaries) {
 419  0
                         if (key.equals(summary.getKey())) {
 420  0
                                 return true;
 421  
                         }
 422  
                 }
 423  0
                 return false;
 424  
         }
 425  
 
 426  
         /**
 427  
          * Return true if there is no object in the ObjectListing under defaultObjectKey.<br>
 428  
          * Return true if the object in the ObjectListing was created by this plugin.<br>
 429  
          * Return false otherwise.<br>
 430  
          */
 431  
         protected boolean isCreateOrUpdateDefaultObject(final S3PrefixContext context) {
 432  0
                 if (!isExistingObject(context.getObjectListing(), context.getDefaultObjectKey())) {
 433  
                         // There is no default object, we are free to create one
 434  0
                         return true;
 435  
                 }
 436  0
                 S3BucketContext s3Context = context.getBucketContext();
 437  
                 // There is a default object, but if it was created by this plugin, we
 438  
                 // still need to update it
 439  0
                 S3Object s3Object = s3Context.getClient().getObject(s3Context.getBucket(), context.getDefaultObjectKey());
 440  0
                 boolean isOurDefaultObject = isOurObject(s3Object);
 441  0
                 IOUtils.closeQuietly(s3Object.getObjectContent());
 442  0
                 if (isOurDefaultObject) {
 443  0
                         return true;
 444  
                 } else {
 445  0
                         return false;
 446  
                 }
 447  
         }
 448  
 
 449  
         /**
 450  
          * Return true if this S3Object was created by this plugin. This is is done by checking the metadata attached to
 451  
          * this object for the presence of a custom value.
 452  
          */
 453  
         protected boolean isOurObject(final S3Object s3Object) {
 454  0
                 ObjectMetadata metadata = s3Object.getObjectMetadata();
 455  0
                 Map<String, String> userMetadata = metadata.getUserMetadata();
 456  0
                 String value = userMetadata.get(S3_INDEX_METADATA_KEY);
 457  0
                 boolean isOurObject = "true".equals(value);
 458  0
                 return isOurObject;
 459  
         }
 460  
 
 461  
         /**
 462  
          * Create a CopyObjectRequest with an ACL set to PublicRead
 463  
          */
 464  
         protected CopyObjectRequest getCopyObjectRequest(final String bucket, final String sourceKey, final String destKey) {
 465  0
                 CopyObjectRequest request = new CopyObjectRequest(bucket, sourceKey, bucket, destKey);
 466  0
                 request.setCannedAccessControlList(CannedAccessControlList.PublicRead);
 467  0
                 return request;
 468  
         }
 469  
 
 470  
         public String getTimezone() {
 471  0
                 return timezone;
 472  
         }
 473  
 
 474  
         public void setTimezone(final String timezone) {
 475  0
                 this.timezone = timezone;
 476  0
         }
 477  
 
 478  
         public String getDateFormat() {
 479  0
                 return dateFormat;
 480  
         }
 481  
 
 482  
         public void setDateFormat(final String dateFormat) {
 483  0
                 this.dateFormat = dateFormat;
 484  0
         }
 485  
 
 486  
         public String getDefaultObject() {
 487  0
                 return defaultObject;
 488  
         }
 489  
 
 490  
         public void setDefaultObject(final String defaultCloudFrontObject) {
 491  0
                 this.defaultObject = defaultCloudFrontObject;
 492  0
         }
 493  
 
 494  
         public String getFileImage() {
 495  0
                 return fileImage;
 496  
         }
 497  
 
 498  
         public void setFileImage(final String fileImage) {
 499  0
                 this.fileImage = fileImage;
 500  0
         }
 501  
 
 502  
         public String getDirectoryImage() {
 503  0
                 return directoryImage;
 504  
         }
 505  
 
 506  
         public void setDirectoryImage(final String directoryImage) {
 507  0
                 this.directoryImage = directoryImage;
 508  0
         }
 509  
 
 510  
         public String getCss() {
 511  0
                 return css;
 512  
         }
 513  
 
 514  
         public void setCss(final String css) {
 515  0
                 this.css = css;
 516  0
         }
 517  
 
 518  
         public boolean isCopyDefaultObjectWithDelimiter() {
 519  0
                 return copyDefaultObjectWithDelimiter;
 520  
         }
 521  
 
 522  
         public void setCopyDefaultObjectWithDelimiter(final boolean copyDefaultObjectWithDelimiter) {
 523  0
                 this.copyDefaultObjectWithDelimiter = copyDefaultObjectWithDelimiter;
 524  0
         }
 525  
 
 526  
         public boolean isCopyDefaultObjectWithoutDelimiter() {
 527  0
                 return copyDefaultObjectWithoutDelimiter;
 528  
         }
 529  
 
 530  
         public void setCopyDefaultObjectWithoutDelimiter(final boolean copyDefaultObjectWithoutDelimiter) {
 531  0
                 this.copyDefaultObjectWithoutDelimiter = copyDefaultObjectWithoutDelimiter;
 532  0
         }
 533  
 
 534  
         public String getCacheControl() {
 535  0
                 return cacheControl;
 536  
         }
 537  
 
 538  
         public void setCacheControl(final String cacheControl) {
 539  0
                 this.cacheControl = cacheControl;
 540  0
         }
 541  
 
 542  
         public String getBrowseHtml() {
 543  0
                 return browseHtml;
 544  
         }
 545  
 
 546  
         public void setBrowseHtml(final String browseHtml) {
 547  0
                 this.browseHtml = browseHtml;
 548  0
         }
 549  
 
 550  
         /**
 551  
          * @return the recurse
 552  
          */
 553  
         public boolean isRecurse() {
 554  0
                 return recurse;
 555  
         }
 556  
 
 557  
         /**
 558  
          * @param recurse
 559  
          *            the recurse to set
 560  
          */
 561  
         public void setRecurse(final boolean recurse) {
 562  0
                 this.recurse = recurse;
 563  0
         }
 564  
 
 565  
         /**
 566  
          * @return the organizationGroupId
 567  
          */
 568  
         public String getOrganizationGroupId() {
 569  0
                 return organizationGroupId;
 570  
         }
 571  
 
 572  
         /**
 573  
          * @param organizationGroupId
 574  
          *            the organizationGroupId to set
 575  
          */
 576  
         public void setOrganizationGroupId(final String organizationGroupId) {
 577  0
                 this.organizationGroupId = organizationGroupId;
 578  0
         }
 579  
 
 580  
         public boolean isUpdateChildModules() {
 581  0
                 return updateChildModules;
 582  
         }
 583  
 
 584  
         public void setUpdateChildModules(boolean updateChildModules) {
 585  0
                 this.updateChildModules = updateChildModules;
 586  0
         }
 587  
 
 588  
 }