\n\u003Ctask:annotation-driven executor=\"myExecutor\" scheduler=\"myScheduler\" />\n\u003Ctask:executor id=\"myExecutor\" pool-size=\"5\" />\n\u003Ctask:scheduler id=\"myScheduler\" pool-size=\"10\" />\n","xml",[2716,8169,8170,8175,8180,8185],{"__ignoreMap":11},[1727,8171,8172],{"class":3110,"line":3111},[1727,8173,8174],{},"\u003Cbean id=\"myClass\" class=\"my.project.path.myClass\" />\n",[1727,8176,8177],{"class":3110,"line":12},[1727,8178,8179],{},"\u003Ctask:annotation-driven executor=\"myExecutor\" scheduler=\"myScheduler\" />\n",[1727,8181,8182],{"class":3110,"line":181},[1727,8183,8184],{},"\u003Ctask:executor id=\"myExecutor\" pool-size=\"5\" />\n",[1727,8186,8187],{"class":3110,"line":3136},[1727,8188,8189],{},"\u003Ctask:scheduler id=\"myScheduler\" pool-size=\"10\" />\n",[76,8191,8193],{"id":8192},"the-scheduled-annotation","The @Scheduled annotation",[42,8195,8196],{},"With the @Scheduled annotation you can execute your method as a cron job. Using this annotation requires that the method\nto be scheduled must be of type void and must not expect any arguments. The following examples show you how to use the\n@Scheduled annotation.",[42,8198,8199],{},"If you want periodic scheduling you can use the property fixedRate. In this example the method would be executed every\n42 seconds.",[3101,8201,8205],{"className":8202,"code":8203,"language":8204,"meta":11,"style":11},"language-java shiki shiki-themes github-light github-dark","@Scheduled(fixedRate = 42000)\npublic void execute() {\n // do something\n}\n","java",[2716,8206,8207,8212,8217,8222],{"__ignoreMap":11},[1727,8208,8209],{"class":3110,"line":3111},[1727,8210,8211],{},"@Scheduled(fixedRate = 42000)\n",[1727,8213,8214],{"class":3110,"line":12},[1727,8215,8216],{},"public void execute() {\n",[1727,8218,8219],{"class":3110,"line":181},[1727,8220,8221],{}," // do something\n",[1727,8223,8224],{"class":3110,"line":3136},[1727,8225,7502],{},[42,8227,8228],{},"If you prefer cron expressions you can use them either. The following example is analogue to the example above only\nusing cron expressions. The annotated method would be executed each full minute and every 7 seconds.",[3101,8230,8232],{"className":8202,"code":8231,"language":8204,"meta":11,"style":11},"@Scheduled(cron = \"*/7 * * * * *\")\npublic void execute() {\n // do something\n}\n",[2716,8233,8234,8239,8243,8247],{"__ignoreMap":11},[1727,8235,8236],{"class":3110,"line":3111},[1727,8237,8238],{},"@Scheduled(cron = \"*/7 * * * * *\")\n",[1727,8240,8241],{"class":3110,"line":12},[1727,8242,8216],{},[1727,8244,8245],{"class":3110,"line":181},[1727,8246,8221],{},[1727,8248,8249],{"class":3110,"line":3136},[1727,8250,7502],{},[42,8252,8253],{},"Without question you have much more possibilities with cron expressions than with periodic scheduling. In this example\nyour method would be executed every weekday (Monday to Friday) on 9.45 am.",[3101,8255,8257],{"className":8202,"code":8256,"language":8204,"meta":11,"style":11},"@Scheduled(cron = \"0 45 9 * * MON-FRI\")\npublic void execute() {\n // do something\n}\n",[2716,8258,8259,8264,8268,8272],{"__ignoreMap":11},[1727,8260,8261],{"class":3110,"line":3111},[1727,8262,8263],{},"@Scheduled(cron = \"0 45 9 * * MON-FRI\")\n",[1727,8265,8266],{"class":3110,"line":12},[1727,8267,8216],{},[1727,8269,8270],{"class":3110,"line":181},[1727,8271,8221],{},[1727,8273,8274],{"class":3110,"line":3136},[1727,8275,7502],{},[42,8277,8278],{},"A pretty cool feature is that you even can use placeholders for your cron expression which are resolved against the\nconfigured property-placeholder.",[3101,8280,8282],{"className":8202,"code":8281,"language":8204,"meta":11,"style":11},"@Scheduled(cron = \"${myclass.cron.execute.sth}\")\npublic void execute() {\n // do something\n}\n",[2716,8283,8284,8289,8293,8297],{"__ignoreMap":11},[1727,8285,8286],{"class":3110,"line":3111},[1727,8287,8288],{},"@Scheduled(cron = \"${myclass.cron.execute.sth}\")\n",[1727,8290,8291],{"class":3110,"line":12},[1727,8292,8216],{},[1727,8294,8295],{"class":3110,"line":181},[1727,8296,8221],{},[1727,8298,8299],{"class":3110,"line":3136},[1727,8300,7502],{},[42,8302,8303],{},"Define where the properties are loaded from within your application context:",[3101,8305,8307],{"className":8165,"code":8306,"language":8167,"meta":11,"style":11},"\u003Ccontext:property-placeholder location=\"classpath:application.properties\"/>\n",[2716,8308,8309],{"__ignoreMap":11},[1727,8310,8311],{"class":3110,"line":3111},[1727,8312,8306],{},[42,8314,8315],{},"Then the properties are loaded from the file which contains your cron-expressions like this:",[3101,8317,8319],{"className":3236,"code":8318,"language":3238,"meta":11,"style":11},"myclass.cron.execute.sth=0 45 9 * * MON-FRI\n",[2716,8320,8321],{"__ignoreMap":11},[1727,8322,8323],{"class":3110,"line":3111},[1727,8324,8318],{},[76,8326,8328],{"id":8327},"the-async-annotation","The @Async annotation",[42,8330,8331],{},"The @Async annotation allows you to invoke your method asynchronously. The execution of the method will occur in a task\nthat has been submitted to the TaskExecutor defined in your application context. Contrary to the methods annotated with\nthe @Scheduled annotations the methods you annotate with @Async may be of other type than void and can expect arguments.",[42,8333,8334],{},"This is a simple example of a @Async annotated method without a return value.",[3101,8336,8338],{"className":8202,"code":8337,"language":8204,"meta":11,"style":11},"@Async\nvoid execute(String string) {\n // do something asynchronously\n}\n",[2716,8339,8340,8345,8350,8355],{"__ignoreMap":11},[1727,8341,8342],{"class":3110,"line":3111},[1727,8343,8344],{},"@Async\n",[1727,8346,8347],{"class":3110,"line":12},[1727,8348,8349],{},"void execute(String string) {\n",[1727,8351,8352],{"class":3110,"line":181},[1727,8353,8354],{}," // do something asynchronously\n",[1727,8356,8357],{"class":3110,"line":3136},[1727,8358,7502],{},[42,8360,8361],{},"Like mentioned above your @Async annotated method may have a return value. However this return value must be of type\nFuture. This means that first the other tasks are performed and then is called get() on that Future.",[3101,8363,8365],{"className":8202,"code":8364,"language":8204,"meta":11,"style":11},"@Async\nFuture\u003CString> execute(String string) {\n // do something asynchronously\n}\n",[2716,8366,8367,8371,8376,8380],{"__ignoreMap":11},[1727,8368,8369],{"class":3110,"line":3111},[1727,8370,8344],{},[1727,8372,8373],{"class":3110,"line":12},[1727,8374,8375],{},"Future\u003CString> execute(String string) {\n",[1727,8377,8378],{"class":3110,"line":181},[1727,8379,8354],{},[1727,8381,8382],{"class":3110,"line":3136},[1727,8383,7502],{},[76,8385,8387],{"id":8386},"further-information","Further information",[42,8389,8390,8391],{},"Have a look at\nthe ",[46,8392,8395],{"href":8393,"rel":8394},"http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#scheduling",[50],"Spring Framework Reference Documentation",[5165,8397,8398],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":11,"searchDepth":12,"depth":12,"links":8400},[8401,8402,8403,8404],{"id":8158,"depth":181,"text":8159},{"id":8192,"depth":181,"text":8193},{"id":8327,"depth":181,"text":8328},{"id":8386,"depth":181,"text":8387},[2981,5187],"2012-06-13T15:49:15","You want to execute cron jobs or call your methods asynchronously? Thanks to Spring’s annotation support for scheduling\\nand asynchronous execution you can achieve this in a few minutes.","https://synyx.de/blog/scheduling-and-asynchronous-execution-with-spring/",{},"/blog/scheduling-and-asynchronous-execution-with-spring",{"title":8146,"description":8155},"blog/scheduling-and-asynchronous-execution-with-spring",[8414,8415,8416,8417,8418,8419],"async","scheduled","asynchronous","scheduling","spring","spring-annotations","You want to execute cron jobs or call your methods asynchronously? Thanks to Spring’s annotation support for scheduling and asynchronous execution you can achieve this in a few minutes. Some…","fzW4lb1yw0kNbXB83aAmQzrzjrslpT-gtiBvUzbdR7Q",{"id":8423,"title":8424,"author":8425,"body":8426,"category":9079,"date":9080,"description":9081,"extension":16,"link":9082,"meta":9083,"navigation":23,"path":9084,"seo":9085,"slug":8430,"stem":9086,"tags":9087,"teaser":9095,"__hash__":9096},"blog/blog/how-to-monitor-and-manage-your-java-application-with-jmx.md","How to monitor and manage your Java application with JMX",[34],{"type":8,"value":8427,"toc":9072},[8428,8431,8434,8449,8525,8528,8532,8535,8625,8628,8635,8639,8653,8658,8663,8686,8689,8694,8699,8723,8726,8749,8754,8759,8783,8789,8828,8837,8841,8844,8849,8852,8858,8863,8866,8872,8875,8878,8912,8915,8965,8969,8972,8975,9036,9039,9043,9049,9056,9063,9070],[38,8429,8424],{"id":8430},"how-to-monitor-and-manage-your-java-application-with-jmx",[42,8432,8433],{},"JMX (Java Management Extensions) provides the infrastructure to support monitoring and management of your Java\napplications. Resources you manage with JMX are called Managed Beans (MBeans). I want to show you how to quickly\nregister your own Service as MBean using Spring and Source-Level Metadata (JDK 5.0+ annotations).",[42,8435,8436,8437,8440,8441,8444,8445,8448],{},"The following sample is built on a tool that allows to manage the staffs’ applications for vacation digitally instead of\nusing paper. If a staff member applies for leave, the application gets the status ",[127,8438,8439],{},"waiting",". Then an authorized person (\nthe boss) has to decide about this application. It may be set to ",[127,8442,8443],{},"allowed"," or to ",[127,8446,8447],{},"rejected",". It might be that you want\nto have an overview of the applications and their status and you may even want to remind the authorized persons via\nemail to review the pending applications. Even if the vacation management tool has a web-based frontend for doing the\nmost of the actions, I think it still makes a good example for describing how to use JMX in your Java application. The\nfollowing class is a skeleton of the class which shall be exposed to JMX as MBean.",[3101,8450,8452],{"className":8202,"code":8451,"language":8204,"meta":11,"style":11},"public class JmxDemo {\n private long numberOfWaitingApplications;\n public long getNumberOfWaitingApplications() {\n return numberOfWaitingApplications;\n }\n public long countApplicationsInStatus(String status) {\n // do something and return number of applications with the given status\n }\n public List\u003CString> showWaitingApplications() {\n // do something and return a list of all waiting applications\n }\n public String remindBossAboutWaitingApplications() {\n // remind the boss via email to decide about the waiting applications\n }\n}\n",[2716,8453,8454,8459,8464,8469,8474,8479,8484,8489,8493,8498,8503,8507,8512,8517,8521],{"__ignoreMap":11},[1727,8455,8456],{"class":3110,"line":3111},[1727,8457,8458],{},"public class JmxDemo {\n",[1727,8460,8461],{"class":3110,"line":12},[1727,8462,8463],{}," private long numberOfWaitingApplications;\n",[1727,8465,8466],{"class":3110,"line":181},[1727,8467,8468],{}," public long getNumberOfWaitingApplications() {\n",[1727,8470,8471],{"class":3110,"line":3136},[1727,8472,8473],{}," return numberOfWaitingApplications;\n",[1727,8475,8476],{"class":3110,"line":3191},[1727,8477,8478],{}," }\n",[1727,8480,8481],{"class":3110,"line":3197},[1727,8482,8483],{}," public long countApplicationsInStatus(String status) {\n",[1727,8485,8486],{"class":3110,"line":3207},[1727,8487,8488],{}," // do something and return number of applications with the given status\n",[1727,8490,8491],{"class":3110,"line":3341},[1727,8492,8478],{},[1727,8494,8495],{"class":3110,"line":3352},[1727,8496,8497],{}," public List\u003CString> showWaitingApplications() {\n",[1727,8499,8500],{"class":3110,"line":3358},[1727,8501,8502],{}," // do something and return a list of all waiting applications\n",[1727,8504,8505],{"class":3110,"line":3364},[1727,8506,8478],{},[1727,8508,8509],{"class":3110,"line":3379},[1727,8510,8511],{}," public String remindBossAboutWaitingApplications() {\n",[1727,8513,8514],{"class":3110,"line":3385},[1727,8515,8516],{}," // remind the boss via email to decide about the waiting applications\n",[1727,8518,8519],{"class":3110,"line":3391},[1727,8520,8478],{},[1727,8522,8523],{"class":3110,"line":3397},[1727,8524,7502],{},[42,8526,8527],{},"If you want to use this class as a MBean, a few steps are necessary.",[76,8529,8531],{"id":8530},"_1-not-yet-another-xml-file","1. Not yet another xml file…",[42,8533,8534],{},"It’s best you create an extra xml file (let’s call it jmxContext.xml) for JMX configuration and import it in your\napplicationContext.xml. In your jmxContext.xml you define your MBean and the MBeanExporter.",[3101,8536,8538],{"className":8165,"code":8537,"language":8167,"meta":11,"style":11},"\n\u003Cbean id=\"jmxDemo\" class=\"org.synyx.urlaubsverwaltung.jmx.JmxDemo\">\n \u003C!-- maybe you need contructor-injection -->\n \u003C!-- \u003Cconstructor-arg ref=\"myService\" /> -->\n\u003C/bean>\n \u003C!-- you may just copy the following lines -->\n\u003Cbean id=\"exporter\" class=\"org.springframework.jmx.export.MBeanExporter\" lazy-init=\"false\">\n\u003Cproperty name=\"autodetect\" value=\"true\"/>\n\u003Cproperty name=\"namingStrategy\" ref=\"namingStrategy\"/>\n\u003Cproperty name=\"assembler\" ref=\"assembler\"/>\n\u003C/bean>\n\u003Cbean id=\"jmxAttributeSource\" class=\"org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource\"/>\n\u003Cbean id=\"assembler\" class=\"org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler\">\n\u003Cproperty name=\"attributeSource\" ref=\"jmxAttributeSource\"/>\n\u003C/bean>\n\u003Cbean id=\"namingStrategy\" class=\"org.springframework.jmx.export.naming.MetadataNamingStrategy\">\n\u003Cproperty name=\"attributeSource\" ref=\"jmxAttributeSource\"/>\n\u003C/bean>\n",[2716,8539,8540,8544,8549,8554,8559,8564,8569,8574,8579,8584,8589,8593,8598,8603,8608,8612,8617,8621],{"__ignoreMap":11},[1727,8541,8542],{"class":3110,"line":3111},[1727,8543,3114],{"emptyLinePlaceholder":23},[1727,8545,8546],{"class":3110,"line":12},[1727,8547,8548],{},"\u003Cbean id=\"jmxDemo\" class=\"org.synyx.urlaubsverwaltung.jmx.JmxDemo\">\n",[1727,8550,8551],{"class":3110,"line":181},[1727,8552,8553],{}," \u003C!-- maybe you need contructor-injection -->\n",[1727,8555,8556],{"class":3110,"line":3136},[1727,8557,8558],{}," \u003C!-- \u003Cconstructor-arg ref=\"myService\" /> -->\n",[1727,8560,8561],{"class":3110,"line":3191},[1727,8562,8563],{},"\u003C/bean>\n",[1727,8565,8566],{"class":3110,"line":3197},[1727,8567,8568],{}," \u003C!-- you may just copy the following lines -->\n",[1727,8570,8571],{"class":3110,"line":3207},[1727,8572,8573],{},"\u003Cbean id=\"exporter\" class=\"org.springframework.jmx.export.MBeanExporter\" lazy-init=\"false\">\n",[1727,8575,8576],{"class":3110,"line":3341},[1727,8577,8578],{},"\u003Cproperty name=\"autodetect\" value=\"true\"/>\n",[1727,8580,8581],{"class":3110,"line":3352},[1727,8582,8583],{},"\u003Cproperty name=\"namingStrategy\" ref=\"namingStrategy\"/>\n",[1727,8585,8586],{"class":3110,"line":3358},[1727,8587,8588],{},"\u003Cproperty name=\"assembler\" ref=\"assembler\"/>\n",[1727,8590,8591],{"class":3110,"line":3364},[1727,8592,8563],{},[1727,8594,8595],{"class":3110,"line":3379},[1727,8596,8597],{},"\u003Cbean id=\"jmxAttributeSource\" class=\"org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource\"/>\n",[1727,8599,8600],{"class":3110,"line":3385},[1727,8601,8602],{},"\u003Cbean id=\"assembler\" class=\"org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler\">\n",[1727,8604,8605],{"class":3110,"line":3391},[1727,8606,8607],{},"\u003Cproperty name=\"attributeSource\" ref=\"jmxAttributeSource\"/>\n",[1727,8609,8610],{"class":3110,"line":3397},[1727,8611,8563],{},[1727,8613,8614],{"class":3110,"line":3403},[1727,8615,8616],{},"\u003Cbean id=\"namingStrategy\" class=\"org.springframework.jmx.export.naming.MetadataNamingStrategy\">\n",[1727,8618,8619],{"class":3110,"line":3409},[1727,8620,8607],{},[1727,8622,8623],{"class":3110,"line":3415},[1727,8624,8563],{},[42,8626,8627],{},"If your application is running inside a container such as Tomcat, you even don’t have to configure the MBeanServer\nbecause the container has its own one.",[42,8629,8630,8631,8634],{},"Setting MBeanExporter’s property ",[127,8632,8633],{},"autodetect"," to true, means that the MBeanExporter will register all the Beans within\nyour application’s context that are annotated in the way described in the next section as MBeans.",[76,8636,8638],{"id":8637},"_2-lets-transform-your-spring-bean-to-a-managed-bean","2. Let’s transform your Spring Bean to a Managed Bean!",[42,8640,8641,8642,8645,8646,8649,8650,172],{},"Spring uses information provided by annotations to generate MBeans. The attributes of the annotations are speaking for\nthemselves so further description isn’t necessary. To mark a Bean for export, it has to be annotated with\n",[127,8643,8644],{},"@ManagedResource",", Attributes are annotated with ",[127,8647,8648],{},"@ManagedAttribute"," and Methods with ",[127,8651,8652],{},"@ManagedOperation",[42,8654,8655],{},[62,8656,8657],{},"2.1 Bean",[42,8659,8660,8661,172],{},"Mark your Bean with ",[127,8662,8644],{},[3101,8664,8666],{"className":8202,"code":8665,"language":8204,"meta":11,"style":11},"@ManagedResource(objectName = \"mbeans:name=myJmxDemoBean\", description = \"My managed Bean.\")\npublic class JmxDemo {\n // lot of stuff\n}\n",[2716,8667,8668,8673,8677,8682],{"__ignoreMap":11},[1727,8669,8670],{"class":3110,"line":3111},[1727,8671,8672],{},"@ManagedResource(objectName = \"mbeans:name=myJmxDemoBean\", description = \"My managed Bean.\")\n",[1727,8674,8675],{"class":3110,"line":12},[1727,8676,8458],{},[1727,8678,8679],{"class":3110,"line":181},[1727,8680,8681],{}," // lot of stuff\n",[1727,8683,8684],{"class":3110,"line":3136},[1727,8685,7502],{},[42,8687,8688],{},"Make sure that your MBean doesn’t contain ‘MBean’ in its name since it would be treated as a StandardMBean causing your\nannotations not to work.",[42,8690,8691],{},[62,8692,8693],{},"2.2 Attributes",[42,8695,8696,8697,172],{},"Annotate the Getter and Setter with ",[127,8698,8648],{},[3101,8700,8702],{"className":8202,"code":8701,"language":8204,"meta":11,"style":11},"@ManagedAttribute(description = \"Get the number of all waiting applications\" )\npublic long getNumberOfWaitingApplications() {\n return numberOfWaitingApplications;\n}\n",[2716,8703,8704,8709,8714,8719],{"__ignoreMap":11},[1727,8705,8706],{"class":3110,"line":3111},[1727,8707,8708],{},"@ManagedAttribute(description = \"Get the number of all waiting applications\" )\n",[1727,8710,8711],{"class":3110,"line":12},[1727,8712,8713],{},"public long getNumberOfWaitingApplications() {\n",[1727,8715,8716],{"class":3110,"line":181},[1727,8717,8718],{}," return numberOfWaitingApplications;\n",[1727,8720,8721],{"class":3110,"line":3136},[1727,8722,7502],{},[42,8724,8725],{},"Exposing attributes may be:",[884,8727,8728,8731,8734,8737,8740,8743,8746],{},[887,8729,8730],{},"Basic types",[887,8732,8733],{},"Primitives and their wrappers",[887,8735,8736],{},"String",[887,8738,8739],{},"BigDecimal",[887,8741,8742],{},"BigInteger",[887,8744,8745],{},"Date",[887,8747,8748],{},"Arrays and collections of basic types",[42,8750,8751],{},[62,8752,8753],{},"2.2 Methods",[42,8755,8756,8757,172],{},"Annotate each method you wish to expose with ",[127,8758,8652],{},[3101,8760,8762],{"className":8202,"code":8761,"language":8204,"meta":11,"style":11},"@ManagedOperation(description = \"Shows a list of all waiting applications with some information.\")\npublic List\u003CString> showWaitingApplications() {\n // do something and return a list of all waiting applications\n}\n",[2716,8763,8764,8769,8774,8779],{"__ignoreMap":11},[1727,8765,8766],{"class":3110,"line":3111},[1727,8767,8768],{},"@ManagedOperation(description = \"Shows a list of all waiting applications with some information.\")\n",[1727,8770,8771],{"class":3110,"line":12},[1727,8772,8773],{},"public List\u003CString> showWaitingApplications() {\n",[1727,8775,8776],{"class":3110,"line":181},[1727,8777,8778],{}," // do something and return a list of all waiting applications\n",[1727,8780,8781],{"class":3110,"line":3136},[1727,8782,7502],{},[42,8784,8785,8786,172],{},"If your methods have parameters you can describe them further with ",[127,8787,8788],{},"@ManagedOperationParameters",[3101,8790,8792],{"className":8202,"code":8791,"language":8204,"meta":11,"style":11},"@ManagedOperation(description = \"Get the number of all applications that have the given status.\")\n@ManagedOperationParameters({\n @ManagedOperationParameter(name = \"status\", description = \"The status may be waiting, allowed, rejected or cancelled.\")\n})\npublic long countApplicationsInStatus(String state) {\n // do something and return number of applications with the given status\n}\n",[2716,8793,8794,8799,8804,8809,8814,8819,8824],{"__ignoreMap":11},[1727,8795,8796],{"class":3110,"line":3111},[1727,8797,8798],{},"@ManagedOperation(description = \"Get the number of all applications that have the given status.\")\n",[1727,8800,8801],{"class":3110,"line":12},[1727,8802,8803],{},"@ManagedOperationParameters({\n",[1727,8805,8806],{"class":3110,"line":181},[1727,8807,8808],{}," @ManagedOperationParameter(name = \"status\", description = \"The status may be waiting, allowed, rejected or cancelled.\")\n",[1727,8810,8811],{"class":3110,"line":3136},[1727,8812,8813],{},"})\n",[1727,8815,8816],{"class":3110,"line":3191},[1727,8817,8818],{},"public long countApplicationsInStatus(String state) {\n",[1727,8820,8821],{"class":3110,"line":3197},[1727,8822,8823],{}," // do something and return number of applications with the given status\n",[1727,8825,8826],{"class":3110,"line":3207},[1727,8827,7502],{},[42,8829,8830,8831,8833,8834,8836],{},"Make sure to annotate your Getter/Setter with ",[127,8832,8648],{}," and not with ",[127,8835,8652],{},". Otherwise your\nmethods won’t work.",[76,8838,8840],{"id":8839},"_3-try-it","3. Try it!",[42,8842,8843],{},"You can now use the functions of your MBean either with JConsole or with other tools. (e.g. JMinix)",[42,8845,8846],{},[62,8847,8848],{},"3.1 JConsole",[42,8850,8851],{},"JConsole is part of Oracle’s JDK, so you can just start it by executing the JConsole command in your JDK’s\nbinary-folder. You can connect to local or to remote Java Virtual Machines. If you are running your application on the\nsame host as JConsole it should show up at the ‘Local Process’ section.",[42,8853,8854],{},[89,8855],{"alt":8856,"src":8857},"\"jconsole\"","https://media.synyx.de/uploads//2012/04/jconsole.png",[42,8859,8860],{},[62,8861,8862],{},"3.2 JMinix",[42,8864,8865],{},"If you want to have a JMX entry point in your web application instead of using JConsole, JMinix might be the right\nchoice for you.",[42,8867,8868],{},[89,8869],{"alt":8870,"src":8871},"\"JMinix\"","https://media.synyx.de/uploads//2012/04/jminix.png",[42,8873,8874],{},"You can include it easily in your Maven based web application:",[42,8876,8877],{},"Add JMinix as dependency in your pom.xml",[3101,8879,8881],{"className":8165,"code":8880,"language":8167,"meta":11,"style":11},"\n\u003Cdependency>\n \u003CgroupId>org.jminix\u003C/groupId>\n \u003CartifactId>jminix\u003C/artifactId>\n \u003Cversion>1.0.0\u003C/version>\n\u003C/dependency>\n",[2716,8882,8883,8887,8892,8897,8902,8907],{"__ignoreMap":11},[1727,8884,8885],{"class":3110,"line":3111},[1727,8886,3114],{"emptyLinePlaceholder":23},[1727,8888,8889],{"class":3110,"line":12},[1727,8890,8891],{},"\u003Cdependency>\n",[1727,8893,8894],{"class":3110,"line":181},[1727,8895,8896],{}," \u003CgroupId>org.jminix\u003C/groupId>\n",[1727,8898,8899],{"class":3110,"line":3136},[1727,8900,8901],{}," \u003CartifactId>jminix\u003C/artifactId>\n",[1727,8903,8904],{"class":3110,"line":3191},[1727,8905,8906],{}," \u003Cversion>1.0.0\u003C/version>\n",[1727,8908,8909],{"class":3110,"line":3197},[1727,8910,8911],{},"\u003C/dependency>\n",[42,8913,8914],{},"JMinix uses a simple HttpServlet that you have to register and map to an url-pattern in your web.xml",[3101,8916,8918],{"className":8165,"code":8917,"language":8167,"meta":11,"style":11},"\u003C!-- JMX -->\n\u003Cservlet>\n \u003Cservlet-name>JmxMiniConsoleServlet\u003C/servlet-name>\n \u003Cservlet-class>org.jminix.console.servlet.MiniConsoleServlet\u003C/servlet-class>\n\u003C/servlet>\n\u003Cservlet-mapping>\n\u003Cservlet-name>JmxMiniConsoleServlet\u003C/servlet-name>\n\u003Curl-pattern>/jmx/*\u003C/url-pattern>\n\u003C/servlet-mapping>\n",[2716,8919,8920,8925,8930,8935,8940,8945,8950,8955,8960],{"__ignoreMap":11},[1727,8921,8922],{"class":3110,"line":3111},[1727,8923,8924],{},"\u003C!-- JMX -->\n",[1727,8926,8927],{"class":3110,"line":12},[1727,8928,8929],{},"\u003Cservlet>\n",[1727,8931,8932],{"class":3110,"line":181},[1727,8933,8934],{}," \u003Cservlet-name>JmxMiniConsoleServlet\u003C/servlet-name>\n",[1727,8936,8937],{"class":3110,"line":3136},[1727,8938,8939],{}," \u003Cservlet-class>org.jminix.console.servlet.MiniConsoleServlet\u003C/servlet-class>\n",[1727,8941,8942],{"class":3110,"line":3191},[1727,8943,8944],{},"\u003C/servlet>\n",[1727,8946,8947],{"class":3110,"line":3197},[1727,8948,8949],{},"\u003Cservlet-mapping>\n",[1727,8951,8952],{"class":3110,"line":3207},[1727,8953,8954],{},"\u003Cservlet-name>JmxMiniConsoleServlet\u003C/servlet-name>\n",[1727,8956,8957],{"class":3110,"line":3341},[1727,8958,8959],{},"\u003Curl-pattern>/jmx/*\u003C/url-pattern>\n",[1727,8961,8962],{"class":3110,"line":3352},[1727,8963,8964],{},"\u003C/servlet-mapping>\n",[76,8966,8968],{"id":8967},"_4-notifications","4. Notifications",[42,8970,8971],{},"Notifications (javax.management.Notification) can be broadcast from your component to notify about something interesting\nhappening. This is only a simple example of using Notifications.",[42,8973,8974],{},"Example: You want to be notified if a user logs in.",[3101,8976,8978],{"className":8202,"code":8977,"language":8204,"meta":11,"style":11},"@ManagedResource(objectName = \"mbeans:name=myJmxDemoBean\", description = \"Manage some 'Urlaubsverwaltung' problems.\")\npublic class JmxDemoReady implements NotificationPublisherAware {\n // lot of stuff\n private NotificationPublisher notificationPublisher;\n public void notifyAboutLogin(String msg) {\n notificationPublisher.sendNotification(new Notification(\"Login Action\", this, 0, msg));\n }\n @Override\n public void setNotificationPublisher(NotificationPublisher notificationPublisher) {\n this.notificationPublisher = notificationPublisher;\n }\n}\n",[2716,8979,8980,8985,8990,8994,8999,9004,9009,9013,9018,9023,9028,9032],{"__ignoreMap":11},[1727,8981,8982],{"class":3110,"line":3111},[1727,8983,8984],{},"@ManagedResource(objectName = \"mbeans:name=myJmxDemoBean\", description = \"Manage some 'Urlaubsverwaltung' problems.\")\n",[1727,8986,8987],{"class":3110,"line":12},[1727,8988,8989],{},"public class JmxDemoReady implements NotificationPublisherAware {\n",[1727,8991,8992],{"class":3110,"line":181},[1727,8993,8681],{},[1727,8995,8996],{"class":3110,"line":3136},[1727,8997,8998],{}," private NotificationPublisher notificationPublisher;\n",[1727,9000,9001],{"class":3110,"line":3191},[1727,9002,9003],{}," public void notifyAboutLogin(String msg) {\n",[1727,9005,9006],{"class":3110,"line":3197},[1727,9007,9008],{}," notificationPublisher.sendNotification(new Notification(\"Login Action\", this, 0, msg));\n",[1727,9010,9011],{"class":3110,"line":3207},[1727,9012,8478],{},[1727,9014,9015],{"class":3110,"line":3341},[1727,9016,9017],{}," @Override\n",[1727,9019,9020],{"class":3110,"line":3352},[1727,9021,9022],{}," public void setNotificationPublisher(NotificationPublisher notificationPublisher) {\n",[1727,9024,9025],{"class":3110,"line":3358},[1727,9026,9027],{}," this.notificationPublisher = notificationPublisher;\n",[1727,9029,9030],{"class":3110,"line":3364},[1727,9031,8478],{},[1727,9033,9034],{"class":3110,"line":3379},[1727,9035,7502],{},[42,9037,9038],{},"With the NotificationPublisher you are able to create Notifications in a very simple way. At the right place in your\ncode, you inject your JmxDemo Bean and call the method notifyAboutLogin() when a user logs in. JConsole now displays a\nthird menu item called ‘Notifications’, besides ‘Attributes’ and ‘Operations’. If you click on ‘Subscribe’, you get a\nNotification every time a user logs in your web application.",[76,9040,9042],{"id":9041},"_5-further-information","5. Further information:",[42,9044,9045],{},[46,9046,8395],{"href":9047,"rel":9048},"http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/jmx.html",[50],[42,9050,9051],{},[46,9052,9055],{"href":9053,"rel":9054},"http://docs.oracle.com/javase/1.5.0/docs/guide/management/jconsole.html",[50],"About JConsole",[42,9057,9058],{},[46,9059,9062],{"href":9060,"rel":9061},"http://code.google.com/p/jminix/",[50],"About JMinix",[42,9064,9065],{},[46,9066,9069],{"href":9067,"rel":9068},"http://blog.synyx.de/2011/11/elektronische-urlaubsverwaltung-made-by-youngsters",[50],"About the vacation management web application",[5165,9071,8398],{},{"title":11,"searchDepth":12,"depth":12,"links":9073},[9074,9075,9076,9077,9078],{"id":8530,"depth":181,"text":8531},{"id":8637,"depth":181,"text":8638},{"id":8839,"depth":181,"text":8840},{"id":8967,"depth":181,"text":8968},{"id":9041,"depth":181,"text":9042},[2981,5187],"2012-05-07T17:56:12","JMX (Java Management Extensions) provides the infrastructure to support monitoring and management of your Java\\napplications. Resources you manage with JMX are called Managed Beans (MBeans). I want to show you how to quickly\\nregister your own Service as MBean using Spring and Source-Level Metadata (JDK 5.0+ annotations).","https://synyx.de/blog/how-to-monitor-and-manage-your-java-application-with-jmx/",{},"/blog/how-to-monitor-and-manage-your-java-application-with-jmx",{"title":8424,"description":8433},"blog/how-to-monitor-and-manage-your-java-application-with-jmx",[9088,9089,9090,9091,9092,9093,9094,8418],"annotation","jconsole","jminix","jmx","mbeans","metadata","notifications","JMX (Java Management Extensions) provides the infrastructure to support monitoring and management of your Java applications. Resources you manage with JMX are called Managed Beans (MBeans). I want to show…","Lf-pqL8fxMUtFEesPQZ2fYbpNoUAqH8DOQaGCkCDsBA",{"id":9098,"title":9099,"author":9100,"body":9101,"category":9254,"date":9255,"description":9256,"extension":16,"link":9257,"meta":9258,"navigation":23,"path":9259,"seo":9260,"slug":9105,"stem":9261,"tags":9262,"teaser":9263,"__hash__":9264},"blog/blog/works-on-my-machine-developing-and-testing-continuous-delivery-with-vagrant.md","'Works on my machine!' – Developing and Testing Continuous Delivery with Vagrant",[26],{"type":8,"value":9102,"toc":9252},[9103,9107,9110,9118,9127,9130,9158,9161,9174,9177,9243,9246,9249],[38,9104,9106],{"id":9105},"works-on-my-machine-developing-and-testing-continuous-delivery-with-vagrant","\"Works on my machine!\" – Developing and Testing Continuous Delivery with Vagrant",[42,9108,9109],{},"I still hear it often in teams, even in agile ones where unit tests, integration tests and continuous integration are\nintegrated in daily work. One team member says it’s working and another with slightly different local environment says\nit’s not. Even more serious: local environments often don’t reflect the deployment environments, for example because the\nfavorite Linux distribution of the developer is not the required server distribution or it just has slightly different\nconfiguration and software versions.",[42,9111,9112,9113,9117],{},"To solve these issues and for testing continuous deployments including provisioning I had an eye\non ",[46,9114,2870],{"href":9115,"rel":9116},"http://vagrantup.com/",[50]," for a while. But with limited time I only tried small test installations until\nrecently.",[42,9119,9120,9121,9126],{},"Our marketing department is quite technical compared to other companies, yet still using non-Linux OS for various\nreasons. To edit and test new content for\nour ",[46,9122,9125],{"href":9123,"rel":9124},"http://blog.synyx.de/2012/03/new-homepage-with-nanoc-twitter-bootstrap-less-and-git/",[50],"homepage"," the local\ncompilation didn’t always work out as expected (tested and deployed on Linux by developers). Perfect testbed for a real\nworld usage of Vagrant.",[42,9128,9129],{},"The goal: Editors just installing Vagrant, updating their repository and starting via vagrant:",[3101,9131,9133],{"className":3103,"code":9132,"language":3105,"meta":11,"style":11},"\ngit clone git://some.repository/path.git\nvagrant up\n\n",[2716,9134,9135,9139,9150],{"__ignoreMap":11},[1727,9136,9137],{"class":3110,"line":3111},[1727,9138,3114],{"emptyLinePlaceholder":23},[1727,9140,9141,9144,9147],{"class":3110,"line":12},[1727,9142,9143],{"class":3125},"git",[1727,9145,9146],{"class":3129}," clone",[1727,9148,9149],{"class":3129}," git://some.repository/path.git\n",[1727,9151,9152,9155],{"class":3110,"line":181},[1727,9153,9154],{"class":3125},"vagrant",[1727,9156,9157],{"class":3129}," up\n",[42,9159,9160],{},"And everything is ready for usage in a started VM, first website already compiled and can be viewed by typing the VM’s\nIP into my local browser.",[42,9162,9163,9164,9168,9169,172],{},"On way might be to prepare a VirtualBox image with everything preinstalled, but the disadvantage is I need to maintain\nthe image with software updates, changes etc. manually. With Vagrant I tell it to use a basic small Debian or Ubuntu box\nwhich is downloaded from given URL and everything is provisioned via ",[46,9165,2746],{"href":9166,"rel":9167},"https://github.com/puppetlabs/puppet",[50],"\nor ",[46,9170,9173],{"href":9171,"rel":9172},"https://github.com/opscode/chef",[50],"Chef",[42,9175,9176],{},"Preparation was a combination of a small Vagrantfile and provisioning via Puppet. My Vagrantfile:",[3101,9178,9182],{"className":9179,"code":9180,"language":9181,"meta":11,"style":11},"language-ruby shiki shiki-themes github-light github-dark","\nVagrant::Config.run do |config|.\n config.vm.box = \"lucid32\"\n config.vm.box_url = \"http://files.vagrantup.com/lucid32.box\"\n config.vm.boot_mode = :gui\n config.vm.network :hostonly, \"192.168.33.10\"\n config.vm.provision :puppet do |puppet|\n puppet.manifests_path = \"puppet/manifests\"\n puppet.module_path = \"puppet/modules\"\n puppet.manifest_file = \"init.pp\"\n end\nend\n\n","ruby",[2716,9183,9184,9188,9193,9198,9203,9208,9213,9218,9223,9228,9233,9238],{"__ignoreMap":11},[1727,9185,9186],{"class":3110,"line":3111},[1727,9187,3114],{"emptyLinePlaceholder":23},[1727,9189,9190],{"class":3110,"line":12},[1727,9191,9192],{},"Vagrant::Config.run do |config|.\n",[1727,9194,9195],{"class":3110,"line":181},[1727,9196,9197],{}," config.vm.box = \"lucid32\"\n",[1727,9199,9200],{"class":3110,"line":3136},[1727,9201,9202],{}," config.vm.box_url = \"http://files.vagrantup.com/lucid32.box\"\n",[1727,9204,9205],{"class":3110,"line":3191},[1727,9206,9207],{}," config.vm.boot_mode = :gui\n",[1727,9209,9210],{"class":3110,"line":3197},[1727,9211,9212],{}," config.vm.network :hostonly, \"192.168.33.10\"\n",[1727,9214,9215],{"class":3110,"line":3207},[1727,9216,9217],{}," config.vm.provision :puppet do |puppet|\n",[1727,9219,9220],{"class":3110,"line":3341},[1727,9221,9222],{}," puppet.manifests_path = \"puppet/manifests\"\n",[1727,9224,9225],{"class":3110,"line":3352},[1727,9226,9227],{}," puppet.module_path = \"puppet/modules\"\n",[1727,9229,9230],{"class":3110,"line":3358},[1727,9231,9232],{}," puppet.manifest_file = \"init.pp\"\n",[1727,9234,9235],{"class":3110,"line":3364},[1727,9236,9237],{}," end\n",[1727,9239,9240],{"class":3110,"line":3379},[1727,9241,9242],{},"end\n",[42,9244,9245],{},"The rest is installed and prepared via puppet modules and manifests on first “vagrant up” which I provide in the\nprojects repository in a puppet/ directory.",[42,9247,9248],{},"With the release of Vagrant 1.0 not long ago I think this has potential for a wider adoption of not only local setups\nof one or multiple VMs for development, but also to test more automation of various kinds for developers, testers,\nsysadmins -> DevOps. On the way to better Continuous Delivery.",[5165,9250,9251],{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":11,"searchDepth":12,"depth":12,"links":9253},[],[5187],"2012-03-23T17:49:14","I still hear it often in teams, even in agile ones where unit tests, integration tests and continuous integration are\\nintegrated in daily work. One team member says it’s working and another with slightly different local environment says\\nit’s not. Even more serious: local environments often don’t reflect the deployment environments, for example because the\\nfavorite Linux distribution of the developer is not the required server distribution or it just has slightly different\\nconfiguration and software versions.","https://synyx.de/blog/works-on-my-machine-developing-and-testing-continuous-delivery-with-vagrant/",{},"/blog/works-on-my-machine-developing-and-testing-continuous-delivery-with-vagrant",{"title":9099,"description":9109},"blog/works-on-my-machine-developing-and-testing-continuous-delivery-with-vagrant",[],"I still hear it often in teams, even in agile ones where unit tests, integration tests and continuous integration are integrated in daily work. One team member says it’s working…","JHm6eMBEOQWSrFbmkFAlA1f-fwO1HK1qxC3rdquHHOU",{"id":9266,"title":9267,"author":9268,"body":9269,"category":9421,"date":9422,"description":9423,"extension":16,"link":9424,"meta":9425,"navigation":23,"path":9426,"seo":9427,"slug":9273,"stem":9428,"tags":9429,"teaser":9434,"__hash__":9435},"blog/blog/new-homepage-with-nanoc-twitter-bootstrap-less-and-git.md","New Homepage with nanoc, Twitter Bootstrap, LESS and Git",[26],{"type":8,"value":9270,"toc":9412},[9271,9274,9277,9286,9289,9293,9296,9305,9308,9312,9331,9335,9338,9342,9351,9355,9364,9368,9371,9380,9383,9386,9395,9398,9407,9410],[38,9272,9267],{"id":9273},"new-homepage-with-nanoc-twitter-bootstrap-less-and-git",[42,9275,9276],{},"With the redesign of our current homepage there was the chance to re-evaluate our requirements and make pragmatic\ndecisions filling our needs.",[42,9278,9279,9280,9285],{},"Our previous websites were always implemented in OpenCms since we are ",[46,9281,9284],{"href":9282,"rel":9283},"https://synyx.de/individualsoftware/",[50],"OpenCms","\nSolution Provider and contributor. Using a CMS like OpenCms seemed the natural decision and it worked well for several\nversions of our homepage. But given the amount of work needed to set it up, develop templates and administrate it, was\nit really what we needed?",[42,9287,9288],{},"A CMS is useful if you have many editors, granular access management with user roles, editor/publisher workflows etc.\nBut we are a team of technically versed people, even our marketing prefers to edit HTML directly instead of rely on a\nWYSIWYG editor where you don’t always know the resulting markup. So OpenCms was a little heavy-weight for our homepage\nwhere we didn’t need most of it’s features.",[54,9290,9292],{"id":9291},"finding-the-right-tool-for-our-needs","Finding the right tool for our needs",[42,9294,9295],{},"Result of analyzing the old homepage was that 99% of it was static content. The only dynamic parts were blog aggregation\nand a contact form. Only for these two it wasn’t worth using a CMS or application framework. Yet we still wanted some\ntemplating and generate static HTML.",[42,9297,9298,9299,9304],{},"There are many static HTML generation tools. I’m not going into detail on which we looked into, just the solution we\ncame up with. Some evaluation lead to ",[46,9300,9303],{"href":9301,"rel":9302},"http://nanoc.stoneship.org/",[50],"nanoc"," which is simple to set-up, supports various\ntemplating formats, is very flexible, has good documentation and is easy to use.",[42,9306,9307],{},"What about the contact form and blog aggregation? Contact forms that only send an email are no added value to an email\naddress. Analysis of it’s usage on the old homepage resulted in that it attracted mainly spam and very few real\nmessages. Blog aggregation is sufficient every few minutes and doesn’t need to be live. So instead of dynamically\nfetching and rendering, it can be done by a cronjob and regenerating server-side.",[54,9309,9311],{"id":9310},"templating","Templating",[42,9313,9314,9315,5938,9320,9324,9325,9330],{},"For templating we\nuse ",[46,9316,9319],{"href":9317,"rel":9318},"https://ruby-doc.org/stdlib/libdoc/erb/rdoc/ERB.html",[50],"“ERB”",[46,9321,9323],{"href":7161,"rel":9322},[50],"“Twitter Bootstrap”","\nand ",[46,9326,9329],{"href":9327,"rel":9328},"https://lesscss.org",[50],"“LESS”"," for CSS. Nanoc supports precompiling LESS and compressing CSS.",[76,9332,9334],{"id":9333},"erb","ERB",[42,9336,9337],{},"ERB is part of Ruby’s standard library and quite similar to JSP templating in the Java world. All we need is HTML, some\nmeta data replacement from pages (e. g. a title) and snippet inclusion for which nanoc provides a rendering helper.",[76,9339,9341],{"id":9340},"less","LESS",[42,9343,9344,9345,9350],{},"LESS enables a more maintainable way of writing CSS since it extends CSS by dynamic behavior such as variables, mixins,\noperations and functions. We chose it over ",[46,9346,9349],{"href":9347,"rel":9348},"http://sass-lang.com/",[50],"SCSS"," because we also use Twitter Bootstrap. I think\nin modern CSS styling you should use either of them to make your CSS maintainable and readable. For example defining our\nnew CI colors as variables or mixins for common button stylings is a good use of these features.",[76,9352,9354],{"id":9353},"twitter-bootstrap","Twitter Bootstrap",[42,9356,9357,9358,9363],{},"The latest popular layouting/css toolkit for common things like a grid layout. In my point of view the main advantage to\nolder CSS frameworks like ",[46,9359,9362],{"href":9360,"rel":9361},"http://960.gs/",[50],"960 Grid System"," is the use of LESS in Twitter Bootstrap, so for example the\ngrid columns can be altered by changing variables.",[54,9365,9367],{"id":9366},"deployment-and-publishing","Deployment and Publishing",[42,9369,9370],{},"We set-up deployment via Git. Basically a Git post-receive hook calls a shell script that loads the correct Ruby\nversion via rvm and executes a rake task:",[3101,9372,9374],{"className":3236,"code":9373,"language":3238,"meta":11,"style":11},"rake deploy:post_receive\n",[2716,9375,9376],{"__ignoreMap":11},[1727,9377,9378],{"class":3110,"line":3111},[1727,9379,9373],{},[42,9381,9382],{},"The rake task then updates dependencies via ‘bundle install’, fetches blog posts via RSS and Tweets via Twitter API,\ncleans up old files and compiles the site via nanoc.",[42,9384,9385],{},"So adding new content or changing some styling is as easy as doing that locally, commiting and publishing by",[3101,9387,9389],{"className":3236,"code":9388,"language":3238,"meta":11,"style":11},"git push stage\n",[2716,9390,9391],{"__ignoreMap":11},[1727,9392,9393],{"class":3110,"line":3111},[1727,9394,9388],{},[42,9396,9397],{},"or",[3101,9399,9401],{"className":3236,"code":9400,"language":3238,"meta":11,"style":11},"git push live\n",[2716,9402,9403],{"__ignoreMap":11},[1727,9404,9405],{"class":3110,"line":3111},[1727,9406,9400],{},[42,9408,9409],{},"The advantage of using Git in this way is not just the easy publishing, but also it’s main feature: versioning. Content\nchanges can be followed, reproduced and rolled back. For example if you have a marketing campaign and styled your page\nin X-mas colors, you can do so in a branch and after New Years you can switch back to the usual styling by switching\nthe branch again.",[5165,9411,8398],{},{"title":11,"searchDepth":12,"depth":12,"links":9413},[9414,9415,9420],{"id":9291,"depth":12,"text":9292},{"id":9310,"depth":12,"text":9311,"children":9416},[9417,9418,9419],{"id":9333,"depth":181,"text":9334},{"id":9340,"depth":181,"text":9341},{"id":9353,"depth":181,"text":9354},{"id":9366,"depth":12,"text":9367},[5187],"2012-03-06T10:59:57","With the redesign of our current homepage there was the chance to re-evaluate our requirements and make pragmatic\\ndecisions filling our needs.","https://synyx.de/blog/new-homepage-with-nanoc-twitter-bootstrap-less-and-git/",{},"/blog/new-homepage-with-nanoc-twitter-bootstrap-less-and-git",{"title":9267,"description":9276},"blog/new-homepage-with-nanoc-twitter-bootstrap-less-and-git",[9430,9431,9143,9125,9340,9303,1175,9432,9181,9433,1176],"cms","css","opencms","styling","With the redesign of our current homepage there was the chance to re-evaluate our requirements and make pragmatic decisions filling our needs. Our previous websites were always implemented in OpenCms…","QKXG5zey8Vf0GGkf5yVxdjTPxZR1fNOEpeJFFbIENL4",{"id":9437,"title":9438,"author":9439,"body":9440,"category":9559,"date":9560,"description":9561,"extension":16,"link":9562,"meta":9563,"navigation":23,"path":9564,"seo":9565,"slug":9444,"stem":9566,"tags":9567,"teaser":9572,"__hash__":9573},"blog/blog/elektronische-urlaubsverwaltung-made-by-youngsters.md","Elektronische Urlaubsverwaltung made by Youngsters",[34],{"type":8,"value":9441,"toc":9557},[9442,9445,9448,9451,9454,9459,9462,9465,9468,9471,9474,9494,9497,9500,9503,9506,9509,9512,9515,9518,9521,9527,9530,9533,9536,9539,9542,9545,9548,9551,9554],[38,9443,9438],{"id":9444},"elektronische-urlaubsverwaltung-made-by-youngsters",[42,9446,9447],{},"Für die erfolgreiche Genehmigung von Urlaub muss der synyx’sche Mitarbeiter sich bisher mit einem Stück Papier alias\n‘schriftlich ausgefüllter Urlaubsantrag’ bewaffnen und sich an einen der drei Chefs anpirschen, um eine Unterschrift zu\nergattern.",[42,9449,9450],{},"Dies ist nicht nur zeitaufwändig, sondern auch einfach nicht zeitgemäß für eine junge Software-Schmiede wie Synyx.",[42,9452,9453],{},"So erhielten Johannes Reuter (Studentische Hilfskraft seit 1. August 2011) und ich, Aljona Murygina (Auszubildende zur\nFachinformatikerin seit 1. August 2011), den Auftrag, das ganze Prozedere zu modernisieren, wir befinden uns\nschließlich im Jahr 2011:",[42,9455,9456],{},[62,9457,9458],{},"Ein Urlaubsverwaltungs-Tool als Webapplikation muss her.",[42,9460,9461],{},"Als Grundgerüst der Applikation wurden drei verschiedene Arten von Usern festgelegt:",[42,9463,9464],{},"der normale User (Antragssteller: Urlaub beantragen),",[42,9466,9467],{},"der Chef (Vergabeberechtigter: Urlaubsantrag genehmigen/ablehnen) und",[42,9469,9470],{},"das Office (eine Art Super-User mit Verwaltungs- und Editierfunktion: Urlaubsantrag bearbeiten).",[42,9472,9473],{},"Essentielle Grundfunktionen des Urlaubsverwaltungs-Tool sollen sein:",[884,9475,9476,9479,9482,9485,9488,9491],{},[887,9477,9478],{},"Die Authentifizierung soll mittels bereits vorhandenen LDAP-Benutzerdaten der Mitarbeiter erfolgen.",[887,9480,9481],{},"Urlaubsanträge sollen digital validiert werden, das heißt Antragssteller und Antraggenehmigender müssen jeweils über\neinen einzigartigen Identifikationsnachweis (‘digitale Unterschrift’) verfügen.",[887,9483,9484],{},"Eine Interaktion mit dem firmeninternen Google-Kalender soll für automatisierte Übersichtlichkeit sorgen, welche\nMitarbeiter in welchem Zeitraum im Urlaub sind.",[887,9486,9487],{},"Transparenz ist die Quintessenz einer Open Source Firma und hört auch nicht bei firmeninternen Vorgängen auf. Daher\nsollen jegliche Schritte der Bearbeitung von Anträgen durch eine Log-Datei nachvollziehbar sein können.",[887,9489,9490],{},"Via E-Mail sollen die jeweils Beteiligten über den laufenden Antragsvorgang informiert werden, ob zum Beispiel ein\nneuer zu genehmigender Antrag vorliegt oder ein Antrag genehmigt wurde.",[887,9492,9493],{},"Urlaubstage per Hand abzuzählen ist ziemlich retro, weshalb im digitalen Urlaubsantrag nur noch via Datumseingabe ein\nZeitraum angegeben werden soll. Über einen Feiertagskalender berechnet dann die Applikation statt der Antragssteller,\nwie viele Urlaubstage netto für diesen Zeitraum vom Urlaubskonto des Mitarbeiters abgezogen werden.",[42,9495,9496],{},"Was die programmatischen Werkzeuge betrifft, wurde uns freie Hand gelassen.",[42,9498,9499],{},"Wir entschieden uns, den Kern des Tools in Java zu schreiben und für die ‘äußere Hülle’ der Webapplikation das Framework\nSpring MVC zu benutzen.",[42,9501,9502],{},"Zunächst erschien uns der Arbeitsauftrag ziemlich trivial.",[42,9504,9505],{},"Bei der Konzeption des Tools allerdings stießen wir doch schnell an einige Stolpersteine.",[42,9507,9508],{},"Zu nennen wäre hier beispielsweise:",[42,9510,9511],{},"Die LDAP-Authentifizierung erschien auf den ersten Blick einfacher, bis wir feststellten, was für ein komplexes und\nweites Feld Spring Security eigentlich darstellt.",[42,9513,9514],{},"Bei der digitalen Validierung wechselten wir mehrmals unsere Meinung. Zur Auswahl verfügbar wäre erstens ein Photo der\neigenen Unterschrift, verknüpft mit der jeweiligen Person, oder zweitens die Signatur mittels eines persönlichen\nPGP-Schlüssels. (momentan favorisieren wir letztere Möglichkeit)",[42,9516,9517],{},"Auch die Interaktion mit einem Google-Kalender ist ein Feld, in das es sich noch einzulesen gilt.",[42,9519,9520],{},"Den inneren Kern unseres Tools, die Domain-Objekte, haben wir nun letztendlich in die Klassen Antrag, Person,\nUrlaubsanspruch und Urlaubskonto gegliedert.",[42,9522,9523],{},[89,9524],{"alt":9525,"src":9526},"\"Domainobjekte\"","https://media.synyx.de/uploads//2011/11/Domainobjekte1.png",[42,9528,9529],{},"Als formelle Stolpersteine bei der Konzeption und Implementierung der Domain-Objekte und Services erwies sich die\nUnterscheidung in ‘normalen’ Urlaub und Resturlaub.",[42,9531,9532],{},"Resturlaub ist übrig gebliebener Jahresurlaub aus dem vorherigen Jahr, den ein Mitarbeiter mit ins neue Jahr nimmt.",[42,9534,9535],{},"Zwei wichtige Daten sind also der 1. Januar und der 1. April.",[42,9537,9538],{},"Am 1. Januar wird aus dem verbliebenem Urlaub des vorigen Jahres Resturlaub, während am 1. April dieser Resturlaub\nverfällt.",[42,9540,9541],{},"Wenn der Urlaubszeitraum also über einen dieser beiden Termine fällt (z.B. Urlaub vom 25.03. – 04.04.), erfordert\ndie Berechnung des Urlaubskontos des Mitarbeiters eine besondere Logik.",[42,9543,9544],{},"Die entsprechenden Services (AntragService, PersonService, UrlaubskontoService) sind großteils schon ausimplementiert,\njedoch ergeben sich aufgrund der Herausforderung der besonderen datumsabhängigen Logik immer wieder Veränderungen im\nCode.",[42,9546,9547],{},"Der MailService ist bisher gelöst mit dem JavaMailSender und MimeMessagePreparator (\norg.springframework.mail.javamail.*), benötigt sicherlich jedoch auch noch eine Überarbeitung der genauen Details.",[42,9549,9550],{},"Controller und die zugehörigen JSPs sind ebenfalls bereits großteils funktionsfähig, z.B. Darstellung von Mitarbeiter-\noder Antragslisten (zum Beispiel nach Status, Person, Datum), Formular zur Antragsstellung.",[42,9552,9553],{},"Das Design betreffend (z.B. dynamische Menü-Navigation oder Kalenderdarstellung ‘DatePicker’) werden wir aller\nWahrscheinlichkeit nach zu Bibliotheken von jQuery greifen.",[42,9555,9556],{},"Bevor wir allerdings überhaupt an das i-Tüpfelchen Design denken können, haben wir noch einen langen Weg vor uns….",{"title":11,"searchDepth":12,"depth":12,"links":9558},[],[2981],"2011-11-07T20:13:06","Für die erfolgreiche Genehmigung von Urlaub muss der synyx’sche Mitarbeiter sich bisher mit einem Stück Papier alias\\n‘schriftlich ausgefüllter Urlaubsantrag’ bewaffnen und sich an einen der drei Chefs anpirschen, um eine Unterschrift zu\\nergattern.","https://synyx.de/blog/elektronische-urlaubsverwaltung-made-by-youngsters/",{},"/blog/elektronische-urlaubsverwaltung-made-by-youngsters",{"title":9438,"description":9447},"blog/elektronische-urlaubsverwaltung-made-by-youngsters",[9568,9569,9570,1176,2692,1178,9571],"ausbildung","azubi-2","spring-mvc","webapplikation","Für die erfolgreiche Genehmigung von Urlaub muss der synyx’sche Mitarbeiter sich bisher mit einem Stück Papier alias ‘schriftlich ausgefüllter Urlaubsantrag’ bewaffnen und sich an einen der drei Chefs anpirschen, um…","Iciij-U2SfXBfMkPBt4jEMrE_4Z6koLV-sClbDtNMa0",{"id":9575,"title":9576,"author":9577,"body":9578,"category":9625,"date":9626,"description":9627,"extension":16,"link":9628,"meta":9629,"navigation":23,"path":9630,"seo":9631,"slug":9632,"stem":9633,"tags":9634,"teaser":9636,"__hash__":9637},"blog/blog/sommerfeier-bei-synyx-eine-nasse-angelegenheit-2.md","Sommerfeier bei Synyx – eine nasse Angelegenheit",[34],{"type":8,"value":9579,"toc":9623},[9580,9583,9592,9595,9600,9603,9606,9609,9614,9617,9620],[38,9581,9576],{"id":9582},"sommerfeier-bei-synyx-eine-nasse-angelegenheit",[42,9584,9585,9589],{},[89,9586],{"alt":9587,"src":9588},"\"Kanu fahren\"","https://media.synyx.de/uploads//2011/08/kanu.jpg",[127,9590,9591],{},"Nicht nur der diesjährige Sommer hat uns oft nasse Bescherung von oben geboten, auch die Sommerfeierei bei Synyx stand\ndieses Jahr ganz im Zeichen des Wassers. Ausflugsziel war nämlich der Altrhein – und zwar nicht zum gemächlichen\nEntenfüttern, sondern zum rasanten Kanufahren in den Stromschnellen des Altrheins.",[42,9593,9594],{},"Für die Meisten war der Startpunkt 13 Uhr im Büro, um sich mit sprudelndem Proviant einzudecken; so eine Kanufahrt macht\nschließlich durstig. Mit der Bahn ging es dann ans Ende der Welt, nach Rappenwörth, wo der Rest der Paddelwilligen zu\nuns stieß. Eine Prise Verwirrung und Ratlosigkeit später („Wo ist denn dieser Kanuverleih überhaupt?“) war unsere Suche\ndoch noch erfolgreich. Wir teilten uns in Zweier- und Dreiergruppen auf und wurden mit Kanus ausgestattet, die wir ans\nUfer hievten, um in See zu stechen. Eines der Kanus bildete sich wohl ein, ein U-Boot zu sein, was zur Folge hatte,\ndass Markus als Erster bis zum Bauch im Wasser stand. Rebecca, ihr Mann und ich sollten das allerdings noch toppen. Denn\nwir fielen beim Einsteigen gleich kopfüber ins Wasser, als unser Kanu kenterte. Zunächst einmal gab es keine weiteren\nOpfer zu beklagen und es hieß für alle: „Volle Fahrt voraus!“.",[42,9596,9597],{},[62,9598,9599],{},"Natürlich wäre gesittetes Benehmen auf dem Kanu viel zu langweilig, weshalb der Altrhein spontan zu einem\nWasserschlachtfeld erklärt wurde.",[42,9601,9602],{},"Feuer lässt sich vielleicht nicht mit Feuer bekämpfen, aber Wasser mit Wasser. Wir lernten schnell, dass sich ein Paddel\nnicht nur zum Paddeln eignet, sondern auch ein sehr effektives Werkzeug zur Bewässerung anderer Kanus und der\nzugehörigen Crew darstellt. Man munkelt, dass das Admin-Kanu noch viel schärfere Geschütze aufgefahren hatte, wie z.B.\nWasserpistolen und Wasserbomben; und ein Megafon hatte wohl sonst auch kein anderes Kanu mit an Bord.",[42,9604,9605],{},"Während der ereignisreichen Seeschlachten hieß es für manche Besatzung leider auch mal: „Mann/Frau über Bord!“ Es steht\nimmer noch Aussage gegen Aussage, wer denn wirklich schuld war am Kentern des Kanus von Thomas, Florian und Lianna; es\ngibt da verschiedene Versionen der Geschichte. Was allerdings sicher feststeht, ist, dass die erwähnten Wasserratten nur\ndurch die Großherzigkeit anderer Besatzungen (anzuführen wären hier das Junggesellen-Kanu, das Admin-Kanu und\nunsereins) gerettet werden konnten – und das gleich zwei Mal innerhalb weniger Minuten.",[42,9607,9608],{},"Während der Fahrt ereilte uns auch tatsächlich noch der angekündigte Regenschauer. Allerdings störte dieser nicht\nweiter, da man ja durch all den Schabernack sowieso schon nass war.",[42,9610,9611],{},[62,9612,9613],{},"Nach circa zweieinhalb Stunden Seeschlacht auf dem Altrhein hatten die vor Brackwasser triefenden Synyx-Piraten\nendlich wieder festen Boden unter den Füßen.",[42,9615,9616],{},"Ein wenig erschöpft und hungrig kehrte man bei den Rheinbrüdern ein. Dort standen schon die Kaltgetränke bereit, während\nder Grill gerade angeschmissen wurde. Neben dem Grillgut hatte das Buffet auch eine Vegetarier-freundliche Auswahl an\nSalaten und Antipasti zu bieten. Als kleines i-Tüpfelchen gab es zum Nachtisch dann noch Kuchen und Eis.",[42,9618,9619],{},"Es wurde reichlich gespeist und getrunken, Seemannsgarn ausgetauscht und miteinander gelacht bis in den Morgen hinein. (\ndie Letzten räumten das Feld gegen drei Uhr früh)",[42,9621,9622],{},"Alles in allem war die Sommerfeier (die gleichzeitig meine erste Feier bei Synyx war) genauso nass wie gelungen, was\nschon viel Vorfreude auf die nächsten Feiern macht.",{"title":11,"searchDepth":12,"depth":12,"links":9624},[],[189],"2011-08-16T13:16:01","Nicht nur der diesjährige Sommer hat uns oft nasse Bescherung von oben geboten, auch die Sommerfeierei bei Synyx stand\\ndieses Jahr ganz im Zeichen des Wassers. Ausflugsziel war nämlich der Altrhein – und zwar nicht zum gemächlichen\\nEntenfüttern, sondern zum rasanten Kanufahren in den Stromschnellen des Altrheins.","https://synyx.de/blog/sommerfeier-bei-synyx-eine-nasse-angelegenheit-2/",{},"/blog/sommerfeier-bei-synyx-eine-nasse-angelegenheit-2",{"title":9576,"description":9591},"sommerfeier-bei-synyx-eine-nasse-angelegenheit-2","blog/sommerfeier-bei-synyx-eine-nasse-angelegenheit-2",[9635,1176],"feier","Nicht nur der diesjährige Sommer hat uns oft nasse Bescherung von oben geboten, auch die Sommerfeierei bei Synyx stand dieses Jahr ganz im Zeichen des Wassers. Ausflugsziel war nämlich der…","uJimB3fTqYzOn4piT2m5_9EK72whVyWNEtrG0jdVEHI",{"id":9639,"title":9640,"author":9641,"body":9642,"category":9661,"date":9663,"description":9664,"extension":16,"link":9665,"meta":9666,"navigation":23,"path":9667,"seo":9668,"slug":9669,"stem":9670,"tags":9671,"teaser":9679,"__hash__":9680},"blog/blog/opensource-is-not-just-about-the-license.md","Being Open Source instead of just Open-Sourcing or Open Source is not just about the license",[26],{"type":8,"value":9643,"toc":9659},[9644,9647,9650,9653],[38,9645,9640],{"id":9646},"being-open-source-instead-of-just-open-sourcing-or-open-source-is-not-just-about-the-license",[42,9648,9649],{},"Open Source is not just about available sources or certain licenses. Successful Open Source projects have a community\nthat matters, not just users, strong leaders that listen and still communicate their vision and goal, growing base of\ncontributors who don’t want to be ignored, even if there’s a benevolent dictator as project lead.",[42,9651,9652],{},"There are some popular Open Source projects which recently failed in some of these areas and got forked. Synyx decided\nto go with the forks even though we are mainly users and in these cases not main contributors. What’s the reason behind\nthese decisions? Our company vision tells us to live Open Source which includes much more than what it looks on its\nsurface. It’s not a goal in itself. We believe openness, communication and trancparency are key to quality software,\nespecially long term. That leads to more deliverable value and improved competitiveness as well as more transparency to\nthe community behind.",[42,9654,9655],{},[89,9656],{"alt":11,"src":9657,"title":9658},"https://media.synyx.de/uploads//2011/05/chili-300x199.jpg","chili",{"title":11,"searchDepth":12,"depth":12,"links":9660},[],[5187,9662],"open-source-blog","2011-05-20T17:01:44","Open Source is not just about available sources or certain licenses. Successful Open Source projects have a community\\nthat matters, not just users, strong leaders that listen and still communicate their vision and goal, growing base of\\ncontributors who don’t want to be ignored, even if there’s a benevolent dictator as project lead.","https://synyx.de/blog/opensource-is-not-just-about-the-license/",{},"/blog/opensource-is-not-just-about-the-license",{"title":9640,"description":9649},"opensource-is-not-just-about-the-license","blog/opensource-is-not-just-about-the-license",[9672,9673,9674,9675,9676,1175,9677,9678],"chiliproject","community","hudson","jenkins","libreoffice","redmine","transparency","Open Source is not just about available sources or certain licenses. Successful Open Source projects have a community that matters, not just users, strong leaders that listen and still communicate…","CCudIs0-B2Q3HB1MJjr6jXo1c__MAyAy4luOsfGU9SQ",{"id":9682,"title":9683,"author":9684,"body":9685,"category":10128,"date":10129,"description":9692,"extension":16,"link":10130,"meta":10131,"navigation":23,"path":10132,"seo":10133,"slug":10134,"stem":10135,"tags":10136,"teaser":10146,"__hash__":10147},"blog/blog/utilizing-git-to-dive-into-huge-code-bases.md","Utilizing Git to dive into huge code bases – Git SVN Tips",[26],{"type":8,"value":9686,"toc":10126},[9687,9690,9693,9696,9699,9713,9716,9719,9722,9725,9728,9731,9734,9737,9740,9743,9746,9749,9752,9755,9758,9761,9764,9778,9808,9811,9814,9817,9831,9833,9847,9850,9853,9879,9882,9925,9928,9931,9934,9953,9981,9984,9987,9990,9993,10017,10020,10034,10061,10064,10067,10070,10073,10096,10104,10118,10121,10124],[38,9688,9683],{"id":9689},"utilizing-git-to-dive-into-huge-code-bases-git-svn-tips",[42,9691,9692],{},"Unfortunately there are still projects not on dvsc like git. That’s especially true",[42,9694,9695],{},"for enterprise customers which are at least stuck on Subversion if not worse.",[42,9697,9698],{},"So the first thing I do on new projects I join:",[3101,9700,9702],{"className":3236,"code":9701,"language":3238,"meta":11,"style":11},"\n git svn clone -s svn-url\n\n",[2716,9703,9704,9708],{"__ignoreMap":11},[1727,9705,9706],{"class":3110,"line":3111},[1727,9707,3114],{"emptyLinePlaceholder":23},[1727,9709,9710],{"class":3110,"line":12},[1727,9711,9712],{}," git svn clone -s svn-url\n",[42,9714,9715],{},"Or installing Git if I have to work on customer provided machines. That’s even more",[42,9717,9718],{},"important than the rest of a development environment like an IDE.",[42,9720,9721],{},"From experience I find it especially useful to experiment with new code basis",[42,9723,9724],{},"utilizing Git. Grown and big projects aren’t easy to understand architecturally and",[42,9726,9727],{},"implementation wise without digging deep. With the help of Git you can jump right",[42,9729,9730],{},"in, without fear and without messing everything up or having too much unrevertable",[42,9732,9733],{},"local changes. Just commit early and often! By doing it locally, in experimental",[42,9735,9736],{},"branches you can try and learn. Before you publish something to a wider audience",[42,9738,9739],{},"(svn) you can reorder, cherrypick and change everything or parts of it. Git is my",[42,9741,9742],{},"tool of choice to get my hands dirty with legacy code (new one too of course).",[42,9744,9745],{},"Some useful tips on how I use Git-SVN:",[42,9747,9748],{},"SVN history is linear, so you can’t use branches and merge the usual git-way without",[42,9750,9751],{},"thinking.",[42,9753,9754],{},"What often happens to me is that I implement a new feature, do some refactorings on",[42,9756,9757],{},"my way etc and an urgant bug report comes along. But I commited on master, don’t",[42,9759,9760],{},"want to push it to SVN yet since it’s not finished yet and might not be stable. What",[42,9762,9763],{},"to do? git svn dcommit would push all my local master commits to svn. The solution:",[3101,9765,9767],{"className":3236,"code":9766,"language":3238,"meta":11,"style":11},"\n git branch featureA\n\n",[2716,9768,9769,9773],{"__ignoreMap":11},[1727,9770,9771],{"class":3110,"line":3111},[1727,9772,3114],{"emptyLinePlaceholder":23},[1727,9774,9775],{"class":3110,"line":12},[1727,9776,9777],{}," git branch featureA\n",[3101,9779,9781],{"className":3236,"code":9780,"language":3238,"meta":11,"style":11},"\u003Ctt>\n |svn | master\n ---o---o---o---o---o---o---o---o---o---o\n | featureA\n\u003C/tt>\n",[2716,9782,9783,9788,9793,9798,9803],{"__ignoreMap":11},[1727,9784,9785],{"class":3110,"line":3111},[1727,9786,9787],{},"\u003Ctt>\n",[1727,9789,9790],{"class":3110,"line":12},[1727,9791,9792],{}," |svn | master\n",[1727,9794,9795],{"class":3110,"line":181},[1727,9796,9797],{}," ---o---o---o---o---o---o---o---o---o---o\n",[1727,9799,9800],{"class":3110,"line":3136},[1727,9801,9802],{}," | featureA\n",[1727,9804,9805],{"class":3110,"line":3191},[1727,9806,9807],{},"\u003C/tt>\n",[42,9809,9810],{},"Now both branches featureA and master point to the latest commit. But we want master",[42,9812,9813],{},"to point to an earlier commit. Let’s say the last 10 commits aren’t in SVN yet and",[42,9815,9816],{},"the last 8 are experimental, so 2 could be pushed.",[3101,9818,9820],{"className":3236,"code":9819,"language":3238,"meta":11,"style":11},"\n git reset --hard HEAD~8\n\n",[2716,9821,9822,9826],{"__ignoreMap":11},[1727,9823,9824],{"class":3110,"line":3111},[1727,9825,3114],{"emptyLinePlaceholder":23},[1727,9827,9828],{"class":3110,"line":12},[1727,9829,9830],{}," git reset --hard HEAD~8\n",[42,9832,9397],{},[3101,9834,9836],{"className":3236,"code":9835,"language":3238,"meta":11,"style":11},"\n git reset --hard sha-hash-of-commit-to-point-to\n\n",[2716,9837,9838,9842],{"__ignoreMap":11},[1727,9839,9840],{"class":3110,"line":3111},[1727,9841,3114],{"emptyLinePlaceholder":23},[1727,9843,9844],{"class":3110,"line":12},[1727,9845,9846],{}," git reset --hard sha-hash-of-commit-to-point-to\n",[42,9848,9849],{},"Now my master is in the state it was in 8 commits ago and my experimental changes",[42,9851,9852],{},"are still in featureA branch.",[3101,9854,9856],{"className":3236,"code":9855,"language":3238,"meta":11,"style":11},"\u003Ctt>\n |svn | master\n ---o---o---o---o---o---o---o---o---o---o\n | featureA\n\u003C/tt>\n",[2716,9857,9858,9862,9867,9871,9875],{"__ignoreMap":11},[1727,9859,9860],{"class":3110,"line":3111},[1727,9861,9787],{},[1727,9863,9864],{"class":3110,"line":12},[1727,9865,9866],{}," |svn | master\n",[1727,9868,9869],{"class":3110,"line":181},[1727,9870,9797],{},[1727,9872,9873],{"class":3110,"line":3136},[1727,9874,9802],{},[1727,9876,9877],{"class":3110,"line":3191},[1727,9878,9807],{},[42,9880,9881],{},"I can continue with fixing that critical bug, commit and svn dcommit. Have a look on how your history look with gitk\n–all.",[3101,9883,9885],{"className":3236,"code":9884,"language":3238,"meta":11,"style":11},"\u003Ctt>\n | svn\n ---o---o---o master\n /\n ---o---o---o\n \\---o---o---o---o---o---o---o\n | featureA\n\u003C/tt>\n",[2716,9886,9887,9891,9896,9901,9906,9911,9916,9921],{"__ignoreMap":11},[1727,9888,9889],{"class":3110,"line":3111},[1727,9890,9787],{},[1727,9892,9893],{"class":3110,"line":12},[1727,9894,9895],{}," | svn\n",[1727,9897,9898],{"class":3110,"line":181},[1727,9899,9900],{}," ---o---o---o master\n",[1727,9902,9903],{"class":3110,"line":3136},[1727,9904,9905],{}," /\n",[1727,9907,9908],{"class":3110,"line":3191},[1727,9909,9910],{}," ---o---o---o\n",[1727,9912,9913],{"class":3110,"line":3197},[1727,9914,9915],{}," \\---o---o---o---o---o---o---o\n",[1727,9917,9918],{"class":3110,"line":3207},[1727,9919,9920],{}," | featureA\n",[1727,9922,9923],{"class":3110,"line":3341},[1727,9924,9807],{},[42,9926,9927],{},"Dcommit rebased 3 commits and especially if",[42,9929,9930],{},"there were some more upstream svn commits, I want to base my experimental stuff",[42,9932,9933],{},"ontop of this. So I do a",[3101,9935,9937],{"className":3236,"code":9936,"language":3238,"meta":11,"style":11},"\n git checkout featureA\n git rebase master\n\n",[2716,9938,9939,9943,9948],{"__ignoreMap":11},[1727,9940,9941],{"class":3110,"line":3111},[1727,9942,3114],{"emptyLinePlaceholder":23},[1727,9944,9945],{"class":3110,"line":12},[1727,9946,9947],{}," git checkout featureA\n",[1727,9949,9950],{"class":3110,"line":181},[1727,9951,9952],{}," git rebase master\n",[3101,9954,9956],{"className":3236,"code":9955,"language":3238,"meta":11,"style":11},"\u003Ctt>\n | master\n ---o---o---o---o---o---o---o---o---o---o---o\n | svn | featureA\n\u003C/tt>\n",[2716,9957,9958,9962,9967,9972,9977],{"__ignoreMap":11},[1727,9959,9960],{"class":3110,"line":3111},[1727,9961,9787],{},[1727,9963,9964],{"class":3110,"line":12},[1727,9965,9966],{}," | master\n",[1727,9968,9969],{"class":3110,"line":181},[1727,9970,9971],{}," ---o---o---o---o---o---o---o---o---o---o---o\n",[1727,9973,9974],{"class":3110,"line":3136},[1727,9975,9976],{}," | svn | featureA\n",[1727,9978,9979],{"class":3110,"line":3191},[1727,9980,9807],{},[42,9982,9983],{},"Even if I could live without the upstream changes on my featureA branch for now, I’d",[42,9985,9986],{},"need a rebase later anyway, so I can do it in advance. That’s because the history",[42,9988,9989],{},"wouldn’t be linear anymore by doing a three-way merge of my featureA into master without rebasing.",[42,9991,9992],{},"When I’m satisfied and with featureA and nothing changed in master I can",[3101,9994,9996],{"className":3236,"code":9995,"language":3238,"meta":11,"style":11},"\n git checkout master\n git merge featureA\n git branch -d featureA\n\n",[2716,9997,9998,10002,10007,10012],{"__ignoreMap":11},[1727,9999,10000],{"class":3110,"line":3111},[1727,10001,3114],{"emptyLinePlaceholder":23},[1727,10003,10004],{"class":3110,"line":12},[1727,10005,10006],{}," git checkout master\n",[1727,10008,10009],{"class":3110,"line":181},[1727,10010,10011],{}," git merge featureA\n",[1727,10013,10014],{"class":3110,"line":3136},[1727,10015,10016],{}," git branch -d featureA\n",[42,10018,10019],{},"And since it’s a fast-forward merge can continue to push it to SVN",[3101,10021,10023],{"className":3236,"code":10022,"language":3238,"meta":11,"style":11},"\n git svn dcommit\n\n",[2716,10024,10025,10029],{"__ignoreMap":11},[1727,10026,10027],{"class":3110,"line":3111},[1727,10028,3114],{"emptyLinePlaceholder":23},[1727,10030,10031],{"class":3110,"line":12},[1727,10032,10033],{}," git svn dcommit\n",[3101,10035,10037],{"className":3236,"code":10036,"language":3238,"meta":11,"style":11},"\u003Ctt>\n | master\n ---o---o---o---o---o---o---o---o---o---o---o\n | svn\n\u003C/tt>\n",[2716,10038,10039,10043,10048,10052,10057],{"__ignoreMap":11},[1727,10040,10041],{"class":3110,"line":3111},[1727,10042,9787],{},[1727,10044,10045],{"class":3110,"line":12},[1727,10046,10047],{}," | master\n",[1727,10049,10050],{"class":3110,"line":181},[1727,10051,9971],{},[1727,10053,10054],{"class":3110,"line":3136},[1727,10055,10056],{}," | svn\n",[1727,10058,10059],{"class":3110,"line":3191},[1727,10060,9807],{},[42,10062,10063],{},"If something did change in master I just do another rebase before the merge.",[42,10065,10066],{},"If I come to the conclusion that my experimental branch was just for learning",[42,10068,10069],{},"purpose and only one or two useful refactoring or unit-test improving commits I take",[42,10071,10072],{},"only these to master and abandon the branch.",[3101,10074,10076],{"className":3236,"code":10075,"language":3238,"meta":11,"style":11},"\n git checkout master\n git cherry-pick sha-of-one-commit\n git cherry-pick sha-of-another\n\n",[2716,10077,10078,10082,10086,10091],{"__ignoreMap":11},[1727,10079,10080],{"class":3110,"line":3111},[1727,10081,3114],{"emptyLinePlaceholder":23},[1727,10083,10084],{"class":3110,"line":12},[1727,10085,10006],{},[1727,10087,10088],{"class":3110,"line":181},[1727,10089,10090],{}," git cherry-pick sha-of-one-commit\n",[1727,10092,10093],{"class":3110,"line":3136},[1727,10094,10095],{}," git cherry-pick sha-of-another\n",[42,10097,10098,10099],{},"If I’m overall satisfied with the results of my experimental branch, but not with commit messages, how the commits are\nordered and maybe their scope, I use git\nrebases ",[46,10100,10103],{"href":10101,"rel":10102},"http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html#_interactive_mode",[50],"interactive mode",[3101,10105,10107],{"className":3236,"code":10106,"language":3238,"meta":11,"style":11},"\n git rebase -i sha-after-this-commit\n\n",[2716,10108,10109,10113],{"__ignoreMap":11},[1727,10110,10111],{"class":3110,"line":3111},[1727,10112,3114],{"emptyLinePlaceholder":23},[1727,10114,10115],{"class":3110,"line":12},[1727,10116,10117],{}," git rebase -i sha-after-this-commit\n",[42,10119,10120],{},"reordering commits, splitting commits, editing commit messages, squashing multiple commits together.",[42,10122,10123],{},"There are endless more possibilities to get a better grip on your code-base.",[5165,10125,8398],{},{"title":11,"searchDepth":12,"depth":12,"links":10127},[],[5187],"2011-03-21T06:22:53","https://synyx.de/blog/utilizing-git-to-dive-into-huge-code-bases/",{},"/blog/utilizing-git-to-dive-into-huge-code-bases",{"title":9683,"description":9692},"utilizing-git-to-dive-into-huge-code-bases","blog/utilizing-git-to-dive-into-huge-code-bases",[10137,9143,10138,10139,10140,10141,10142,10143,10144,10145],"dvcs","productivity","software-development","subversion","svn","tips","vcs","versioncontrol","withoutfear","Unfortunately there are still projects not on dvsc like git. That’s especially true for enterprise customers which are at least stuck on Subversion if not worse. So the first thing…","jY0wlPCOmzUfKbhiV6O6parFyGSU5NhgtbhpJnpQyIQ",{"id":10149,"title":10150,"author":10151,"body":10152,"category":10308,"date":10309,"description":10310,"extension":16,"link":10311,"meta":10312,"navigation":23,"path":10313,"seo":10314,"slug":10156,"stem":10315,"tags":10316,"teaser":10317,"__hash__":10318},"blog/blog/bash-prompt-for-git.md","Bash-Prompt for Git",[26],{"type":8,"value":10153,"toc":10306},[10154,10157,10160,10166,10301,10304],[38,10155,10150],{"id":10156},"bash-prompt-for-git",[42,10158,10159],{},"Since Florian Hopf asked me today how I made my Bash prompt show the current git branch, here’s the relevant .bashrc\npart (which evloved from code found on some other blogs I don’t remember anymore).",[42,10161,10162],{},[89,10163],{"alt":10164,"src":10165},"\"screenshot_git_bashpromt\"","https://media.synyx.de/uploads//2011/01/screenshot_git_bashpromt.png",[3101,10167,10169],{"className":3236,"code":10168,"language":3238,"meta":11,"style":11},"function parse_git_branch {\ngit branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \\(.*\\)/(\\1)/'\n}\nfunction promptl {\nlocal BLUE=\"\\[\\033[0;34m\\]\"\nlocal RED=\"\\[\\033[0;31m\\]\"\nlocal LIGHT_RED=\"\\[\\033[1;31m\\]\"\nlocal GREEN=\"\\[\\033[0;32m\\]\"\nlocal LIGHT_GREEN=\"\\[\\033[1;32m\\]\"\nlocal WHITE=\"\\[\\033[1;37m\\]\"\nlocal LIGHT_GRAY=\"\\[\\033[0;37m\\]\"\ncase $TERM in\nxterm*)\nTITLEBAR='\\[\\033]0;\\u@\\h:\\w\\007\\]'\n;;\n*)\nTITLEBAR=\"\"\n;;\nesac\nPS1=\"${TITLEBAR}\\\n$BLUE[$RED\\$(date +%H:%M)$BLUE]\\\n$BLUE[$RED\\u@\\h:\\w$GREEN\\$(parse_git_branch)$BLUE]\\\n$GREEN\\$ $LIGHT_GRAY\"\nPS2='> '\nPS4='+ '\n}\npromptl\n",[2716,10170,10171,10176,10181,10185,10190,10195,10200,10205,10210,10215,10220,10225,10230,10235,10240,10244,10249,10254,10258,10262,10267,10272,10277,10282,10287,10292,10296],{"__ignoreMap":11},[1727,10172,10173],{"class":3110,"line":3111},[1727,10174,10175],{},"function parse_git_branch {\n",[1727,10177,10178],{"class":3110,"line":12},[1727,10179,10180],{},"git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \\(.*\\)/(\\1)/'\n",[1727,10182,10183],{"class":3110,"line":181},[1727,10184,7502],{},[1727,10186,10187],{"class":3110,"line":3136},[1727,10188,10189],{},"function promptl {\n",[1727,10191,10192],{"class":3110,"line":3191},[1727,10193,10194],{},"local BLUE=\"\\[\\033[0;34m\\]\"\n",[1727,10196,10197],{"class":3110,"line":3197},[1727,10198,10199],{},"local RED=\"\\[\\033[0;31m\\]\"\n",[1727,10201,10202],{"class":3110,"line":3207},[1727,10203,10204],{},"local LIGHT_RED=\"\\[\\033[1;31m\\]\"\n",[1727,10206,10207],{"class":3110,"line":3341},[1727,10208,10209],{},"local GREEN=\"\\[\\033[0;32m\\]\"\n",[1727,10211,10212],{"class":3110,"line":3352},[1727,10213,10214],{},"local LIGHT_GREEN=\"\\[\\033[1;32m\\]\"\n",[1727,10216,10217],{"class":3110,"line":3358},[1727,10218,10219],{},"local WHITE=\"\\[\\033[1;37m\\]\"\n",[1727,10221,10222],{"class":3110,"line":3364},[1727,10223,10224],{},"local LIGHT_GRAY=\"\\[\\033[0;37m\\]\"\n",[1727,10226,10227],{"class":3110,"line":3379},[1727,10228,10229],{},"case $TERM in\n",[1727,10231,10232],{"class":3110,"line":3385},[1727,10233,10234],{},"xterm*)\n",[1727,10236,10237],{"class":3110,"line":3391},[1727,10238,10239],{},"TITLEBAR='\\[\\033]0;\\u@\\h:\\w\\007\\]'\n",[1727,10241,10242],{"class":3110,"line":3397},[1727,10243,3637],{},[1727,10245,10246],{"class":3110,"line":3403},[1727,10247,10248],{},"*)\n",[1727,10250,10251],{"class":3110,"line":3409},[1727,10252,10253],{},"TITLEBAR=\"\"\n",[1727,10255,10256],{"class":3110,"line":3415},[1727,10257,3637],{},[1727,10259,10260],{"class":3110,"line":3420},[1727,10261,3642],{},[1727,10263,10264],{"class":3110,"line":3426},[1727,10265,10266],{},"PS1=\"${TITLEBAR}\\\n",[1727,10268,10269],{"class":3110,"line":3432},[1727,10270,10271],{},"$BLUE[$RED\\$(date +%H:%M)$BLUE]\\\n",[1727,10273,10274],{"class":3110,"line":3443},[1727,10275,10276],{},"$BLUE[$RED\\u@\\h:\\w$GREEN\\$(parse_git_branch)$BLUE]\\\n",[1727,10278,10279],{"class":3110,"line":3449},[1727,10280,10281],{},"$GREEN\\$ $LIGHT_GRAY\"\n",[1727,10283,10284],{"class":3110,"line":3455},[1727,10285,10286],{},"PS2='> '\n",[1727,10288,10289],{"class":3110,"line":3460},[1727,10290,10291],{},"PS4='+ '\n",[1727,10293,10294],{"class":3110,"line":3480},[1727,10295,7502],{},[1727,10297,10298],{"class":3110,"line":3971},[1727,10299,10300],{},"promptl\n",[42,10302,10303],{},"Feel free to copy into your .bashrc to have a colored prompt showing the current git branch if you are in a git\nrepository.",[5165,10305,8398],{},{"title":11,"searchDepth":12,"depth":12,"links":10307},[],[189],"2011-01-14T18:15:05","Since Florian Hopf asked me today how I made my Bash prompt show the current git branch, here’s the relevant .bashrc\\npart (which evloved from code found on some other blogs I don’t remember anymore).","https://synyx.de/blog/bash-prompt-for-git/",{},"/blog/bash-prompt-for-git",{"title":10150,"description":10159},"blog/bash-prompt-for-git",[],"Since Florian Hopf asked me today how I made my Bash prompt show the current git branch, here’s the relevant .bashrc part (which evloved from code found on some other…","kPwut3xxxpA6o-JCIvAwJftzlQDqVbvWODS2_rP53OY",{"id":10320,"title":10321,"author":10322,"body":10323,"category":10432,"date":10433,"description":10434,"extension":16,"link":10435,"meta":10436,"navigation":23,"path":10437,"seo":10438,"slug":10439,"stem":10440,"tags":10441,"teaser":10446,"__hash__":10447},"blog/blog/scrum-an-anti-word.md","Why is Scrum getting an anti-word?",[26],{"type":8,"value":10324,"toc":10427},[10325,10328,10331,10334,10341,10346,10352,10355,10381,10384,10388,10391,10394,10397,10400,10403,10406,10409,10412,10415,10418,10421,10424],[38,10326,10321],{"id":10327},"why-is-scrum-getting-an-anti-word",[42,10329,10330],{},"For quite some years Scrum has been THE agile development process. Scrum got mainstream. But let’s have a look what got\nmainstream here. Scrum, Agility, Buzzwords, Scrum Master got mainstream as words, in business talk, in dev talk, in\ntrainings.",[42,10332,10333],{},"But what did it really achive for better communication, better relations and collaboration between developers, managers,\ncustomers etc. Has Scrum fundamentally improved the way software is delivered in our industry?",[42,10335,10336,10337,10340],{},"I probably couldn’t find many people who’d respond with an unconditional “",[62,10338,10339],{},"YES!","” to this question.",[42,10342,10343],{},[62,10344,10345],{},"But why? Why is Scrum getting an anti-word for many?",[42,10347,10348],{},[89,10349],{"alt":10350,"src":10351},"\"Security!\"","http://defunctscrum.blogspot.com/2007/07/should-you-leave-scrum-off-resume.html",[42,10353,10354],{},"There are various different reasons:",[884,10356,10357,10360,10363,10366,10369,10372,10375,10378],{},[887,10358,10359],{},"Scrum’s transparency creats angst for people living in and from intransparency",[887,10361,10362],{},"Scrum’s need for change is uncomfortable for people’s need for stability",[887,10364,10365],{},"Wrong implementation of Scrum",[887,10367,10368],{},"Scrum Master who don’t take people with them and run ahead in their own speed",[887,10370,10371],{},"Unbalanced power division between roles",[887,10373,10374],{},"Scrum Master who have THE solution instead of enabling teams to find differing ways for different problems",[887,10376,10377],{},"The Scrum hype and overwhelming/missleading marketing",[887,10379,10380],{},"Could go on with lots more",[42,10382,10383],{},"Let’s focus on a few and look at them a little bit more in-depth.",[76,10385,10387],{"id":10386},"speedy-scrum-master","Speedy Scrum Master",[42,10389,10390],{},"A person who just got his Scrum Master Certificate and gets all enthusiastic about it returns to his company from\ntraining and wants to start. His textbook knowledge tells him how to technically implement Scrum, but without years of\nexperience it’s applied in a step-by-step way. Without soft-skills and knowing what’s appropriate when it’s allmost\nimpossible to be successful right away without watering down Scrum to non-Scrum. Picking people up where they are is\none of the key things. You can’t just tell them where they ought to be without telling why and what for.",[42,10392,10393],{},"Once this poor Scrum Master introduced Scrum to team for a few sprints he and his team will hit walls without knowing\nhow to climb over them. At this point the lack of experience of the Scrum Master leads to the first internal critics to\nsurface. The longer a Scrum Master only has his Scrum process goal in mind without providing real solutions the more\nScrum will be the scapegoat.",[42,10395,10396],{},"The more this happens (and I guess it does a lot), the more people will say “Oh no, not another of these Scrum guys”.",[76,10398,10371],{"id":10399},"unbalanced-power-division-between-roles",[42,10401,10402],{},"Unbalanced power division between roles causes wrong implementation and frustration.",[42,10404,10405],{},"For example Scrum Masters who don’t have the support of upper management to make things happen.",[42,10407,10408],{},"Teams without the power to stop a sprint, without the needed skills and not cross-functional are handicapped teams.",[42,10410,10411],{},"Product Owner who are not directly responsible for the profit and loss or ROI of the product. I often wonder how a\nProduct Owner is supposed to prioritize without? I still often hear something along the lines “we need everything!”.",[42,10413,10414],{},"One of the things that’s done wrong in projects that use Scrum is that Scrum should help a project to fail early instead\nof staying for a long time and dying a long slow death over years. Why’s that? Because often all people involved have\nconflicting interests regarding their job safety and early project death. The only one that could have an interest in\nthat is a Product Owner with budget responsibility who knows that a project shouldn’t be continued if the value of to be\nimplemented stories is lower than its costs.",[76,10416,10377],{"id":10417},"the-scrum-hype-and-overwhelmingmissleading-marketing",[42,10419,10420],{},"Scrum is often advertised as solution for everything. Scrum has been hyped for years. The result is lots of so called\n‘experts’ promote and implement Scrum without ensuring it’s done right or often even without the experience on how to do\nit right. Again Scrum gets the blame for failing projects that might or might not have failed anyway.",[42,10422,10423],{},"So is Scrum at fault? Or is it the way Scrum is used today? Can Scrum be rescued or do we need something new just\nbecause Scrum is done wrong instead of because it is wrong?",[42,10425,10426],{},"As with so many things I think we should focus more on quality instead of quantity. Don’t look for cookbook receipts,\nlet your team tailor their process inside the Scrum skeleton and share (don’t force it) your experience with them. I\nmight follow up on this in a future article.",{"title":11,"searchDepth":12,"depth":12,"links":10428},[10429,10430,10431],{"id":10386,"depth":181,"text":10387},{"id":10399,"depth":181,"text":10371},{"id":10417,"depth":181,"text":10377},[5187],"2010-05-20T12:57:24","For quite some years Scrum has been THE agile development process. Scrum got mainstream. But let’s have a look what got\\nmainstream here. Scrum, Agility, Buzzwords, Scrum Master got mainstream as words, in business talk, in dev talk, in\\ntrainings.","https://synyx.de/blog/scrum-an-anti-word/",{},"/blog/scrum-an-anti-word",{"title":10321,"description":10330},"scrum-an-anti-word","blog/scrum-an-anti-word",[10442,10443,10444,10445,10139],"agile","anti-scrum","processes","scrum","For quite some years Scrum has been THE agile development process. Scrum got mainstream. But let’s have a look what got mainstream here. Scrum, Agility, Buzzwords, Scrum Master got mainstream…","61KWdx6d7036gQMdieWCu_XLPod6Mrrx0FD70e-o9Jk",["Reactive",10449],{"$scookieConsent":10450,"$ssite-config":10452},{"functional":10451,"analytics":10451},false,{"_priority":10453,"env":10457,"name":10458,"url":10459},{"name":10454,"env":10455,"url":10456},-10,-15,0,"production","nuxt-app","https://synyx.de",["Set"],["ShallowReactive",10462],{"author-buch":-1,"roughlyFilteredArticles":-1},"/blog/author/buch"]