001 /* 002 * Copyright (c) 2007-2014 Concurrent, Inc. All Rights Reserved. 003 * 004 * Project and contact information: http://www.cascading.org/ 005 * 006 * This file is part of the Cascading project. 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020 021 package cascading.property; 022 023 import java.util.Map; 024 import java.util.Properties; 025 import java.util.Set; 026 import java.util.TreeSet; 027 028 import cascading.util.Util; 029 import org.slf4j.Logger; 030 import org.slf4j.LoggerFactory; 031 032 import static cascading.util.Util.join; 033 034 /** 035 * Class AppProps is a fluent helper for setting various application level properties that every 036 * {@link cascading.flow.Flow} may or may not be required to have set. These properties are typically passed to a Flow 037 * via a {@link cascading.flow.FlowConnector}. 038 * <p/> 039 * New property settings that may be set in Cascading 2 are application name, version, and any tags. 040 * <p/> 041 * See {@link #addTag(String)} for examples of using tags to help manage an application. 042 * <p/> 043 * In prior releases, the FlowConnector was responsible for setting the "application jar" class or path. Those 044 * methods have been deprecated and moved to AppProps. 045 */ 046 public class AppProps extends Props 047 { 048 private static final Logger LOG = LoggerFactory.getLogger( AppProps.class ); 049 050 public static final String APP_ID = "cascading.app.id"; 051 public static final String APP_NAME = "cascading.app.name"; 052 public static final String APP_VERSION = "cascading.app.version"; 053 public static final String APP_TAGS = "cascading.app.tags"; 054 public static final String APP_FRAMEWORKS = "cascading.app.frameworks"; 055 public static final String APP_JAR_CLASS = "cascading.app.appjar.class"; 056 public static final String APP_JAR_PATH = "cascading.app.appjar.path"; 057 058 static final String DEP_APP_JAR_CLASS = "cascading.flowconnector.appjar.class"; 059 static final String DEP_APP_JAR_PATH = "cascading.flowconnector.appjar.path"; 060 061 // need a global unique value here 062 private static String appID; 063 064 protected String name; 065 protected String version; 066 protected Set<String> tags = new TreeSet<String>(); 067 protected Class jarClass; 068 protected String jarPath; 069 protected Set<String> frameworks = new TreeSet<String>(); 070 071 /** 072 * Creates a new AppProps instance. 073 * 074 * @return AppProps instance 075 */ 076 public static AppProps appProps() 077 { 078 return new AppProps(); 079 } 080 081 /** 082 * Method setApplicationJarClass is used to set the application jar file. 083 * </p> 084 * All cluster executed Cascading applications 085 * need to call setApplicationJarClass(java.util.Map, Class) or 086 * {@link #setApplicationJarPath(java.util.Map, String)}, otherwise ClassNotFound exceptions are likely. 087 * 088 * @param properties of type Map 089 * @param type of type Class 090 */ 091 public static void setApplicationJarClass( Map<Object, Object> properties, Class type ) 092 { 093 if( type != null ) 094 properties.put( APP_JAR_CLASS, type ); 095 } 096 097 /** 098 * Method getApplicationJarClass returns the Class set by the setApplicationJarClass method. 099 * 100 * @param properties of type Map<Object, Object> 101 * @return Class 102 */ 103 public static Class getApplicationJarClass( Map<Object, Object> properties ) 104 { 105 Class property = PropertyUtil.getProperty( properties, DEP_APP_JAR_CLASS, (Class) null ); 106 107 if( property != null ) 108 { 109 LOG.warn( "using deprecated property: {}, use instead: {}", DEP_APP_JAR_CLASS, APP_JAR_CLASS ); 110 return property; 111 } 112 113 return PropertyUtil.getProperty( properties, APP_JAR_CLASS, (Class) null ); 114 } 115 116 /** 117 * Method setApplicationJarPath is used to set the application jar file. 118 * </p> 119 * All cluster executed Cascading applications 120 * need to call {@link #setApplicationJarClass(java.util.Map, Class)} or 121 * setApplicationJarPath(java.util.Map, String), otherwise ClassNotFound exceptions are likely. 122 * 123 * @param properties of type Map 124 * @param path of type String 125 */ 126 public static void setApplicationJarPath( Map<Object, Object> properties, String path ) 127 { 128 if( path != null ) 129 properties.put( APP_JAR_PATH, path ); 130 } 131 132 /** 133 * Method getApplicationJarPath return the path set by the setApplicationJarPath method. 134 * 135 * @param properties of type Map<Object, Object> 136 * @return String 137 */ 138 public static String getApplicationJarPath( Map<Object, Object> properties ) 139 { 140 String property = PropertyUtil.getProperty( properties, DEP_APP_JAR_PATH, (String) null ); 141 142 if( property != null ) 143 { 144 LOG.warn( "using deprecated property: {}, use instead: {}", DEP_APP_JAR_PATH, APP_JAR_PATH ); 145 return property; 146 } 147 148 return PropertyUtil.getProperty( properties, APP_JAR_PATH, (String) null ); 149 } 150 151 public static void setApplicationID( Map<Object, Object> properties ) 152 { 153 properties.put( APP_ID, getAppID() ); 154 } 155 156 public static String getApplicationID( Map<Object, Object> properties ) 157 { 158 if( properties == null ) 159 return getAppID(); 160 161 return PropertyUtil.getProperty( properties, APP_ID, getAppID() ); 162 } 163 164 private static String getAppID() 165 { 166 if( appID == null ) 167 { 168 appID = Util.createUniqueID(); 169 LOG.info( "using app.id: {}", appID ); 170 } 171 172 return appID; 173 } 174 175 /** Sets the static appID value to null. For debugging purposes. */ 176 public static void resetAppID() 177 { 178 appID = null; 179 } 180 181 public static void setApplicationName( Map<Object, Object> properties, String name ) 182 { 183 if( name != null ) 184 properties.put( APP_NAME, name ); 185 } 186 187 public static String getApplicationName( Map<Object, Object> properties ) 188 { 189 return PropertyUtil.getProperty( properties, APP_NAME, (String) null ); 190 } 191 192 public static void setApplicationVersion( Map<Object, Object> properties, String version ) 193 { 194 if( version != null ) 195 properties.put( APP_VERSION, version ); 196 } 197 198 public static String getApplicationVersion( Map<Object, Object> properties ) 199 { 200 return PropertyUtil.getProperty( properties, APP_VERSION, (String) null ); 201 } 202 203 public static void addApplicationTag( Map<Object, Object> properties, String tag ) 204 { 205 if( tag == null ) 206 return; 207 208 String tags = PropertyUtil.getProperty( properties, APP_TAGS, (String) null ); 209 210 if( tags != null ) 211 tags = join( ",", tag.trim(), tags ); 212 else 213 tags = tag; 214 215 properties.put( APP_TAGS, tags ); 216 } 217 218 public static String getApplicationTags( Map<Object, Object> properties ) 219 { 220 return PropertyUtil.getProperty( properties, APP_TAGS, (String) null ); 221 } 222 223 /** 224 * Adds a framework "name:version" string to the property set and to the System properties. 225 * <p/> 226 * Properties may be null. Duplicates are removed. 227 * 228 * @param properties may be null, additionally adds to System properties 229 * @param framework "name:version" String 230 */ 231 public static void addApplicationFramework( Map<Object, Object> properties, String framework ) 232 { 233 if( framework == null ) 234 return; 235 236 String frameworks = PropertyUtil.getProperty( properties, APP_FRAMEWORKS, System.getProperty( APP_FRAMEWORKS ) ); 237 238 if( frameworks != null ) 239 frameworks = join( ",", framework.trim(), frameworks ); 240 else 241 frameworks = framework; 242 243 frameworks = Util.unique( frameworks, "," ); 244 245 if( properties != null ) 246 properties.put( APP_FRAMEWORKS, frameworks ); 247 248 System.setProperty( APP_FRAMEWORKS, frameworks ); 249 } 250 251 public static String getApplicationFrameworks( Map<Object, Object> properties ) 252 { 253 return PropertyUtil.getProperty( properties, APP_FRAMEWORKS, System.getProperty( APP_FRAMEWORKS ) ); 254 } 255 256 public AppProps() 257 { 258 } 259 260 /** 261 * Sets the name and version of this application. 262 * 263 * @param name of type String 264 * @param version of type String 265 */ 266 public AppProps( String name, String version ) 267 { 268 this.name = name; 269 this.version = version; 270 } 271 272 /** 273 * Method setName sets the application name. 274 * <p/> 275 * By default the application name is derived from the jar name (values before the version in most Maven 276 * compatible jars). 277 * 278 * @param name type String 279 * @return this 280 */ 281 public AppProps setName( String name ) 282 { 283 this.name = name; 284 285 return this; 286 } 287 288 /** 289 * Method setVersion sets the application version. 290 * <p/> 291 * By default the application version is derived from the jar name (values after the name in most Maven 292 * compatible jars). 293 * 294 * @param version type String 295 * @return this 296 */ 297 public AppProps setVersion( String version ) 298 { 299 this.version = version; 300 301 return this; 302 } 303 304 public String getTags() 305 { 306 return join( tags, "," ); 307 } 308 309 /** 310 * Method addTag will associate a "tag" with this application. Applications can have an unlimited number of tags. 311 * <p/> 312 * Tags allow applications to be searched and organized by management tools. 313 * <p/> 314 * Tag values are opaque, but adopting a simple convention of 'category:value' allows for complex use cases. 315 * <p/> 316 * Some recommendations for categories are: 317 * <p/> 318 * <ul> 319 * <lli>cluster: - the cluster name the application is or should be run against. A name could be logical, like QA or PROD.</lli> 320 * <lli>project: - the project name, possibly a JIRA project name this application is managed under.</lli> 321 * <lli>org: - the group, team or organization that is responsible for the application.</lli> 322 * <lli>support: - the email address of the user who should be notified of failures or issues.</lli> 323 * </ul> 324 * 325 * @param tag type String 326 * @return this 327 */ 328 public AppProps addTag( String tag ) 329 { 330 if( !Util.isEmpty( tag ) ) 331 tags.add( tag ); 332 333 return this; 334 } 335 336 /** 337 * Method addTags will associate the given "tags" with this application. Applications can have an unlimited number of tags. 338 * <p/> 339 * Tags allow applications to be searched and organized by management tools. 340 * <p/> 341 * Tag values are opaque, but adopting a simple convention of 'category:value' allows for complex use cases. 342 * <p/> 343 * Some recommendations for categories are: 344 * <p/> 345 * <ul> 346 * <lli>cluster: - the cluster name the application is or should be run against. A name could be logical, like QA or PROD.</lli> 347 * <lli>project: - the project name, possibly a JIRA project name this application is managed under.</lli> 348 * <lli>org: - the group, team or organization that is responsible for the application.</lli> 349 * <lli>support: - the email address of the user who should be notified of failures or issues.</lli> 350 * </ul> 351 * 352 * @param tags type String 353 * @return this 354 */ 355 public AppProps addTags( String... tags ) 356 { 357 for( String tag : tags ) 358 addTag( tag ); 359 360 return this; 361 } 362 363 /** 364 * Method getFrameworks returns a list of frameworks used to build this App. 365 * 366 * @return Registered frameworks 367 */ 368 public String getFrameworks() 369 { 370 return join( frameworks, "," ); 371 } 372 373 /** 374 * Method addFramework adds a new framework name to the list of frameworks used. 375 * <p/> 376 * Higher level tools should register themselves, and preferably with their version, 377 * for example {@code foo-flow-builder:1.2.3}. 378 * <p/> 379 * See {@link #addFramework(String, String)}. 380 * 381 * @param framework A String 382 * @return this AppProps instance 383 */ 384 public AppProps addFramework( String framework ) 385 { 386 if( !Util.isEmpty( framework ) ) 387 frameworks.add( framework ); 388 389 return this; 390 } 391 392 /** 393 * Method addFramework adds a new framework name and its version to the list of frameworks used. 394 * <p/> 395 * Higher level tools should register themselves, and preferably with their version, 396 * for example {@code foo-flow-builder:1.2.3}. 397 * 398 * @param framework A String 399 * @return this AppProps instance 400 */ 401 public AppProps addFramework( String framework, String version ) 402 { 403 if( !Util.isEmpty( framework ) && !Util.isEmpty( version ) ) 404 frameworks.add( framework + ":" + version ); 405 406 if( !Util.isEmpty( framework ) ) 407 frameworks.add( framework ); 408 409 return this; 410 } 411 412 /** 413 * Method addFrameworks adds new framework names to the list of frameworks used. 414 * <p/> 415 * Higher level tools should register themselves, and preferably with their version, 416 * for example {@code foo-flow-builder:1.2.3}. 417 * 418 * @param frameworks Strings 419 * @return this AppProps instance 420 */ 421 public AppProps addFrameworks( String... frameworks ) 422 { 423 for( String framework : frameworks ) 424 addFramework( framework ); 425 426 return this; 427 } 428 429 /** 430 * Method setJarClass is used to set the application jar file. 431 * </p> 432 * All cluster executed Cascading applications 433 * need to call setApplicationJarClass(java.util.Map, Class) or 434 * {@link #setApplicationJarPath(java.util.Map, String)}, otherwise ClassNotFound exceptions are likely. 435 * 436 * @param jarClass of type Class 437 */ 438 public AppProps setJarClass( Class jarClass ) 439 { 440 this.jarClass = jarClass; 441 442 return this; 443 } 444 445 /** 446 * Method setJarPath is used to set the application jar file. 447 * </p> 448 * All cluster executed Cascading applications 449 * need to call {@link #setJarClass(Class)} or 450 * setJarPath(java.util.Map, String), otherwise ClassNotFound exceptions are likely. 451 * 452 * @param jarPath of type String 453 */ 454 public AppProps setJarPath( String jarPath ) 455 { 456 this.jarPath = jarPath; 457 458 return this; 459 } 460 461 @Override 462 protected void addPropertiesTo( Properties properties ) 463 { 464 setApplicationID( properties ); 465 setApplicationName( properties, name ); 466 setApplicationVersion( properties, version ); 467 addApplicationTag( properties, getTags() ); 468 addApplicationFramework( properties, getFrameworks() ); 469 setApplicationJarClass( properties, jarClass ); 470 setApplicationJarPath( properties, jarPath ); 471 } 472 }