Removing HPROF dump files

LC_bugRevisiting the topic of Livecycle consuming everything in its path, I found another issue that features in Livecycle ES4 SP1. The symptoms are the usual symptoms; lack of disk space, server crashing, etc. After hunting down all of the extra large files in your system you might find a number of very large files in the following path:

[livecycle_install_dir]/crx-repository/launchpad/felix/bundle33/dumps

HPROF Files

Heap dump off

To turn this feature off, do the following:

  1. Browse to the AEM system console: http://host:port/lc/system/console
  2. Locate the bundle
    org.apache.felix.webconsole.plugins.memoryusage
  3. Stop the bundle

You can then stop Livecycle, delete the HPROF files and restart Livecycle. The bundle should not restart, but its worth checking anyway.

Changing default server ports in Livecycle ES4 JBoss

JBoss Livecycle ES4 JBoss (including Turnkey) changed the underlying application server to JBoss EAP 5.1.0 and later to 5.2.0 in the SP1 release. This changed the way you alter the port vales for various services. Instead of looking in various different places for the port values, they amalgamated them all into one central configuration file.

The file is located in [server]/conf/bindingservice.beans/META-INF/bindings-jboss-beans.xml

Mastertheboss has a great page about the new Jboss port configuration for JBoss EAP 5.1+ – check it out!

 

Dropbox, Skype and Livecycle

command-prompt-glossyI recently noticed that Livecycle (JBoss) on my development laptop would frequently not start up correctly. It would throw all sorts of errors about ports already in use (1099, etc) and throw a complete wobbly. So I decided to dig around using TcpView and Process Explorer. It seems that Skype and Dropbox (to a lesser extent) would sometimes come in and steal some Livecycle ports when they run. Strangely, it didn’t reproduce every time I went looking for them but I saw enough to see that either one would try to grab the Naming Service port (1099) for some reason.

As both Skype and Dropbox started automatically on my laptop, I inevitably tried to run Livecycle without thinking and it would bomb out. So I decided it was easier to just quit both Dropbox and Skype until after Livecycle had started, then restart those processes when I needed them. They seemed to work fine without the RMI port anyway.

I knocked up a quick batch file to detect if either process was running and kill these apps before running Livecycle so I thought I’d share it. Props go to StackOverflow for the process detection script.

@ECHO OFF
tasklist /FI "IMAGENAME eq dropbox.exe" 2>NUL | find /I /N "dropbox.exe">NUL
if NOT "%ERRORLEVEL%"=="0" goto TEST_SKYPE
echo Dropbox is running...DIE!!
taskkill /f /im "dropbox.exe"

:TEST_SKYPE
tasklist /FI "IMAGENAME eq skype.exe" 2>NUL | find /I /N "skype.exe">NUL
if NOT "%ERRORLEVEL%"=="0" goto START_LC
echo Skype is running...DIE!!
taskkill /f /im "skype.exe"

:START_LC
net start "MySQL for Adobe LiveCycle ES4"
net start JBOSS_FOR_ADOBE_LIVECYCLE_ES4

:EXIT0
pause

Automatically clean JBoss tmp directory

JBoss_by_Red_Hat I have been poking about JBoss lately trying to get messaging working and I had a look in the %JBOSS_HOME%/server/lc_turnkey/tmp directory. As you would imagine, it was chock full of temporary files (no surprise there). What I didn’t expect was how many files! So after a quick email to Adobe Support to confirm I wasn’t going to upset anything Livecycle related, I shut down JBoss and decided to clean the files out. Sometime into the delete, I got bored and lost count at 82,000 files and something like 6GB of space!

JBoss EAP 5.1.0

I had a quick Google around and it took me to a post on the JBoss Community Forum about deleting out files on a JBoss redeploy. Another user mentions that the tmp directory is never purged on restart or starting and stopping JBoss as it was in previous versions. The recommendation was to edit the run.bat file to do this every time the server is started.

The fix

The suggestion was to delete the files before JBoss starts up in the run.bat file. This example is for JBoss on Windows, but its pretty easy to adapt for Linux (just edit the run.sh file instead)

Below is the excerpt from my C:\Adobe\Adobe LiveCycle ES4\jboss\bin\run.bat

pushd %DIRNAME%..
if "x%JBOSS_HOME%" == "x" (
  set "JBOSS_HOME=%CD%"
)
popd

rem Remove tmp folder on startup
set TMP_FOLDER=%JBOSS_HOME%\server\lc_turnkey\tmp
rmdir "%TMP_FOLDER%" /s /q

set DIRNAME=

if "%OS%" == "Windows_NT" (
  set "PROGNAME=%~nx0%"
) else (
  set "PROGNAME=run.bat"
)

Using Quartz as a cron scheduler for LiveCycle

LCA lot of projects I have worked on have required the ability to schedule a LiveCycle short-lived process to run at a particular time of the day and on particular days. Normally, running a script on any platform is a fairly trivial exercise as you have Task Manager in Windows (ugh) and cron under all Linux and Unix variants.  Being an old SCO OpenServer System V admin, cron is by far my scheduler of choice and people have ported cron over to Windows in binaries such as nnCron and CRONw just to name two. But it still requires you to do something outside of LiveCycle to hook it into your processes. Doing this on Windows can get quite complicated as you have to use batch files to execute PowerShell scripts with security disabled and by the end you just want to have a shower afterwards because its such a hack-a-thon. There had to be a cleaner, more integrated way to do this.

DSC is the key

So I knew LiveCycle ES4 Turnkey runs on JBoss EAP 5.1.0 and that comes with the Quartz Scheduler built in. It dawned on me that I could make use of this from within LiveCycle natively. The key was to use a Component DSC to create your very own scheduler. DSC’s can implement the LifeCycle Interface that contains onStart() and onStop() functions that run whenever the DSC or LiveCycle is started or stopped. So why not use this feature to start and stop your own Quartz Scheduler and plug in whatever Jobs needed doing?

Finding Quartz

First thing I did was locate the version of Quartz that JBoss was running. I scanned the server.log file and found this entry:

2013-08-07 19:20:12,195 INFO [org.quartz.core.QuartzScheduler] (main) Quartz Scheduler v.1.5.2 created.
2013-08-07 19:20:12,204 INFO [org.quartz.simpl.RAMJobStore] (main) RAMJobStore initialized.
2013-08-07 19:20:12,207 INFO [org.quartz.impl.DirectSchedulerFactory] (main) Quartz scheduler 'SimpleQuartzScheduler
2013-08-07 19:20:12,207 INFO [org.quartz.impl.DirectSchedulerFactory] (main) Quartz scheduler version: 1.5.2
2013-08-07 19:20:12,210 INFO [org.quartz.core.QuartzScheduler] (main) Scheduler SimpleQuartzScheduler_$_SIMPLE_NON_CLUSTERED started.

Quartz v1.5.2 was pretty old but would still serve for the purposes I wanted it for. Curiously, the IDPSchedulerService was using v1.6.0 and I dug around for this version, but it seems to be only for use by Adobe’s DSC1, so I left that alone. Also I noticed that deep in the crx-repository there was a Quartz v2.1.1 but I doubted that will be available from within JBoss either.

Creating a test DSC

I started by creating a standard DSC project in Eclipse and included the quartz.jar file I found in C:\Adobe\Adobe LiveCycle ES4\jboss\common\lib (I wont go into how you create a DSC here but this guide is a good place as any to start).

I started by creating a simple CustomSchedulerService class (SchedulerService was already taken by an Adobe DSC) to start and stop the Quartz Scheduler:

import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;

public class CustomSchedulerServiceImpl {

	private static Scheduler scheduler;

	/**
	 * Starts the Quartz Scheduler
	 */
	public static void startScheduler() {
		try {
			SchedulerFactory schedFact = new StdSchedulerFactory();

			scheduler = schedFact.getScheduler();
			scheduler.start();

		} catch (SchedulerException se) {
			se.printStackTrace();
		}
	}

	/**
	 * Stops the Quartz Scheduler
	 */
	public static void stopScheduler() {
		try {
			scheduler.shutdown();
		} catch (SchedulerException se) {
			se.printStackTrace();
		}
	}
}

Then I added the startScheduler() and stopScheduler() methods to LifeCycleImpl.java:

package com.btes.lc.dsc;

import java.util.logging.Level;
import com.adobe.idp.dsc.component.ComponentContext;
import com.adobe.idp.dsc.component.LifeCycle;
import com.adobe.logging.AdobeLogger;
import com.btes.lc.dsc.customschedulerservice.CustomSchedulerServiceImpl;

public class LifeCycleImpl implements LifeCycle {

	private static final AdobeLogger logger = AdobeLogger
			.getAdobeLogger(LifeCycleImpl.class);

	private ComponentContext m_ctx;

	public void setComponentContext(ComponentContext aCtx) {
		if (logger.isLoggable(Level.FINE)) {
			logger.log(Level.FINE, "setComponentContext: "
					+ aCtx.getComponent().getComponentId());
		}
		m_ctx = aCtx;
	}

	public void onStart() {
		logger.log(Level.INFO, "Called onStart: "
				+ m_ctx.getComponent().getComponentId());
		//start up our Quartz scheduler
		CustomSchedulerServiceImpl.startScheduler();
	}

	public void onStop() {
		logger.log(Level.INFO, "Called onStop: "
				+ m_ctx.getComponent().getComponentId());
		//shutdown the scheduler
		CustomSchedulerServiceImpl.stopScheduler();
	}
}

Created a simple component.xml file:

<component xmlns="http://adobe.com/idp/dsc/component/document">
	<component-id>com.btes.lc.dsc.customschedulerservice.CustomSchedulerService</component-id>
	<version>1.0</version>
	<bootstrap-class>com.btes.lc.dsc.BootstrapImpl</bootstrap-class>
	<lifecycle-class>com.btes.lc.dsc.LifeCycleImpl</lifecycle-class>
	<services>
		<service name="CustomSchedulerService" orchestrateable="true" title="CustomSchedulerService">
			<implementation-class>com.btes.lc.dsc.customschedulerservice.CustomSchedulerServiceImpl</implementation-class>
			<auto-deploy major-version="1" minor-version="0" category-id="CustomScheduler" />
			<operations>
			</operations>
		</service>
	</services>
	<supports-export>true</supports-export>
   <class-path>quartz.jar</class-path>
</component>

I then did a quick build and installed and started the Component into LiveCycle via Workbench and voila!

2013-08-07 22:22:56,610 INFO  [com.btes.lc.dsc.LifeCycleImpl] (http-0.0.0.0-8080-5) Called onStart: com.btes.lc.dsc.customschedulerservice.CustomSchedulerService
2013-08-07 22:22:56,616 INFO  [org.quartz.simpl.SimpleThreadPool] (http-0.0.0.0-8080-5) Job execution threads will use class loader of thread: http-0.0.0.0-8080-5
2013-08-07 22:22:56,618 INFO  [org.quartz.core.QuartzScheduler] (http-0.0.0.0-8080-5) Quartz Scheduler v.1.5.2 created.
2013-08-07 22:22:56,618 INFO  [org.quartz.simpl.RAMJobStore] (http-0.0.0.0-8080-5) RAMJobStore initialized.
2013-08-07 22:22:56,618 INFO  [org.quartz.impl.StdSchedulerFactory] (http-0.0.0.0-8080-5) Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
2013-08-07 22:22:56,618 INFO  [org.quartz.impl.StdSchedulerFactory] (http-0.0.0.0-8080-5) Quartz scheduler version: 1.5.2
2013-08-07 22:22:56,618 INFO  [org.quartz.core.QuartzScheduler] (http-0.0.0.0-8080-5) Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.

Stopping the DSC also stopped the scheduler:

2013-08-07 22:27:03,949 INFO  [com.adobe.idp.dsc.registry.service.impl.ServiceRegistryImpl] (http-0.0.0.0-8080-5) ServiceRegistryImpl:stop(CustomSchedulerService, 1.0)
2013-08-07 22:27:03,982 INFO  [com.btes.lc.dsc.LifeCycleImpl] (http-0.0.0.0-8080-5) Called onStop: com.btes.lc.dsc.customschedulerservice.CustomSchedulerService
2013-08-07 22:27:03,982 INFO  [org.quartz.core.QuartzScheduler] (http-0.0.0.0-8080-5) Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
2013-08-07 22:27:03,982 INFO  [org.quartz.core.QuartzScheduler] (http-0.0.0.0-8080-5) Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
2013-08-07 22:27:03,982 INFO  [org.quartz.core.QuartzScheduler] (http-0.0.0.0-8080-5) Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.

I am assuming that DefaultQuartzScheduler is the name assigned inside the default quartz.properties configuration file that is inside the quartz.jar file provided by JBoss.

Do something

Next I created a simple Job file that I would eventually use to invoke a process. For now it will just print some output into the server.log at regular intervals.

package com.btes.lc.dsc.customschedulerservice.jobs;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
 * Simple Process Job for Livecycle
 *
 */
public class ProcessJob implements Job {

	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		String jobKey = context.getJobDetail().getName();
		String date = new Date().toString();
		System.out.println("ProcessJob says: " + jobKey + " executing at " + date);
	}
}

Then I would need a Trigger to start the Job which I put into the main Component code for now and scheduled the job as soon as the Scheduler was started. The cron expression "0/20 * * * * ?" would execute the CronTrigger every 20 seconds until the scheduler was stopped.

package com.btes.lc.dsc.customschedulerservice;

import java.text.ParseException;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import com.btes.lc.dsc.customschedulerservice.jobs.ProcessJob;

public class CustomSchedulerServiceImpl implements CustomSchedulerService {

	private static Scheduler scheduler;

	/**
	 * Starts the Quartz Scheduler
	 */
	public static void startScheduler() {
		try {
			SchedulerFactory schedFact = new StdSchedulerFactory();

			scheduler = schedFact.getScheduler();
			scheduler.start();

			CustomSchedulerServiceImpl.scheduleJobs();

		} catch (SchedulerException se) {
			se.printStackTrace();
		}
	}

	/**
	 * Stops the Quartz Scheduler
	 */
	public static void stopScheduler() {
		try {
			scheduler.shutdown();
		} catch (SchedulerException se) {
			se.printStackTrace();
		}
	}

	/**
	 * Schedules some jobs
	 */
	public static void scheduleJobs() {
		try {
			JobDetail job = new JobDetail("myJob", Scheduler.DEFAULT_GROUP, ProcessJob.class);
			CronTrigger trigger = new CronTrigger();
			trigger.setCronExpression("0/20 * * * * ?");
			trigger.setGroup(Scheduler.DEFAULT_GROUP);
			trigger.setName("Trigger1");

			scheduler.scheduleJob(job, trigger);

		} catch (SchedulerException se) {
			se.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}
}

Compiling this code and deploying it to the LiveCycle server gave this output to STDOUT:

2013-08-07 22:45:00,017 INFO  [STDOUT] (DefaultQuartzScheduler_Worker-7) ProcessJob says: myJob executing at Wed Aug 07 22:45:00 EST 2013
2013-08-07 22:45:20,019 INFO  [STDOUT] (DefaultQuartzScheduler_Worker-8) ProcessJob says: myJob executing at Wed Aug 07 22:45:20 EST 2013

Now to make it really DoSomething

Next, I created a very simple application within Workbench that would accept some input and write that out to the server.log file. Crucially, this input should come from the Quartz Scheduler.

SchedulerTest Application

SchedulerTest Application

The executeScript process just grabs the two incoming parameters (inJobName and inDate) and writes them to STDOUT in the server.log file.

System.out.println("SchedulerTest::DoSomething - I am doing something with: "
+ patExecContext.getProcessDataStringValue("/process_data/@inJobName")
+ " invoked on " + patExecContext.getProcessDataStringValue("/process_data/@inDate"));

Next I added the relevant libraries to my Eclipse project and the code to invoke the LiveCycle process to the Job:

package com.btes.lc.dsc.customschedulerservice.jobs;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import com.adobe.idp.dsc.DSCException;
import com.adobe.idp.dsc.InvocationRequest;
import com.adobe.idp.dsc.InvocationResponse;
import com.adobe.idp.dsc.clientsdk.ServiceClient;
import com.adobe.idp.dsc.clientsdk.ServiceClientFactory;
import com.adobe.idp.dsc.clientsdk.ServiceClientFactoryProperties;

/**
 * Simple Process Job for Livecycle
 *
 */
public class ProcessJob implements Job {

	@Override
	public void execute(JobExecutionContext context)
			throws JobExecutionException {
		String jobKey = context.getJobDetail().getName();
		String date = new Date().toString();
		System.out.println("ProcessJob says: " + jobKey + " executing at " + date);

		Properties ConnectionProps = new Properties();
		ConnectionProps.setProperty(
				ServiceClientFactoryProperties.DSC_DEFAULT_EJB_ENDPOINT,
				"jnp://localhost:1099");
		ConnectionProps.setProperty(
				ServiceClientFactoryProperties.DSC_TRANSPORT_PROTOCOL,
				ServiceClientFactoryProperties.DSC_EJB_PROTOCOL);
		ConnectionProps.setProperty(
				ServiceClientFactoryProperties.DSC_SERVER_TYPE, "JBoss");
		ConnectionProps.setProperty(
				ServiceClientFactoryProperties.DSC_CREDENTIAL_USERNAME,
				"administrator");
		ConnectionProps.setProperty(
				ServiceClientFactoryProperties.DSC_CREDENTIAL_PASSWORD,
				"password");

		ServiceClientFactory myFactory = ServiceClientFactory
				.createInstance(ConnectionProps);

		ServiceClient myServiceClient = myFactory.getServiceClient();

		// Create a Map object to store the parameter value

		Map params = new HashMap();

		// Populate the Map object with a parameter value
		params.put("inJobName", context.getJobDetail().getName());
		params.put("inDate", date);

		// Create an InvocationRequest object
		InvocationRequest esRequest = myFactory.createInvocationRequest(
				"SchedulerTest/DoSomething", // Specify the LiveCycle ES process name
				"invoke", // Specify the operation name
				params, // Specify input values
				true); // Create a synchronous request

		// Send the invocation request to the process and
		// get back an invocation response object
		try {
			InvocationResponse esResponse = myServiceClient.invoke(esRequest);
		} catch (DSCException e) {
			e.printStackTrace();
		}
	}
}

I deployed both the Application and the DSC to LiveCycle. I started the DSC and got this as the output:

2013-08-07 23:06:00,020 INFO  [STDOUT] (DefaultQuartzScheduler_Worker-9) ProcessJob says: myJob executing at Wed Aug 07 23:06:00 EST 2013
2013-08-07 23:06:00,060 INFO  [STDOUT] (DefaultQuartzScheduler_Worker-9) SchedulerTest::DoSomething - I am doing something with: myJob invoked on Wed Aug 07 23:06:00 EST 2013
2013-08-07 23:06:20,015 INFO  [STDOUT] (DefaultQuartzScheduler_Worker-9) ProcessJob says: myJob executing at Wed Aug 07 23:06:20 EST 2013
2013-08-07 23:06:20,047 INFO  [STDOUT] (DefaultQuartzScheduler_Worker-9) SchedulerTest::DoSomething - I am doing something with: myJob invoked on Wed Aug 07 23:06:20 EST 2013

As you can see, the CronTrigger ran the ProcessJob every 20 seconds which in turn invoked the LiveCycle process. I’m happy!

Where to from here?

This is obviously a very basic proof-of-concept to show that invoking a LiveCycle process using cron expressions is possible natively from within Livecycle on JBoss. There are a number of things you would need to do to harden this up like use your own quartz.properties file as well as extend it for all sorts of custom configuration. There are plugins for Quartz that allow you to create an XML file to define your jobs and pass in all of the required information to start, stop and handle the execution of those jobs properly. It wouldn’t be a complex exercise to set this up.

Sample files

Below is the sample LCA and the DSC source that I created for this exercise. The libraries are for ES3/ADEP and ES4 but if you replace the libs with ES2.5 libraries, the code should also work.

CustomSchedulerService.zip

SchedulerTest.lca

1 I dug around some more and the IDPSchedulerService does indeed bundle a version of v1.6.0 of quartz.jar inside the adobe-scheduler-jboss.jar which makes me wonder if its possible to replace the v1.5.2 version in JBoss with a later v1.8.5 without breaking anything LiveCycle related…

Move Workbench application storage location

ScreenShot012

By default, Workbench stores any Applications that it retrieves from the LiveCycle server into your user profile directory. In some circumstances this isn’t ideal. Maybe you have a domain policy that restricts your profile space or you want them stored on a network drive so they are backed up.

As Workbench is just eclipse, you can move the workspace folder wherever you want, but Adobe disabled the menu items to do this in the GUI (because you would never want to change your workspace directory ever – right?)

Just add this line to the workbench.ini file (usually located in the C:\Program Files (x86)\Adobe LiveCycle Workbench ES4\workbench folder – or wherever you installed Workbench)

-Duser.home=[yourNewPath]

e.g.

-Duser.home=D:\Workspaces\

LiveCycle configuration parameters – Part 1

What is a configuration parameter?

LiveCycle configuration parameters are one of the most useful and overlooked tools in the Enterprise LiveCycle developer’s toolbox. Simply put, they allow you to edit application variables from the Administration interface (AdminUI) to directly apply to the application you have developed and deployed to the LiveCycle server. This allows you to easily make changes to the application after deployment without having to change, re-deploy and test the application.

Configuration parameters (Adobe Docs)

Why would I use one?

1. Best Practices

As a developer, it is always good practice to make your applications as highly portable and uncoupled from the environment as possible which, in practice, means never hard-coding properties like directories, usernames, passwords, URI’s, etc. that your application may use during run-time. There are limitations in every environment that make this unavoidable in practice (LiveCycle is no exception here) but as a general rule, you should never hard-code any configuration or environment properties in your application.

2. Change Control

In an environment that has a very tight change control process in place this can be invaluable. Raising a change request for an application configuration change is always an easier prospect than one requiring a new build version.

When should I use a configuration parameter?

Configuration parameters should always be used where something could possibly change in the environment that you have deployed your application into.

Some examples:

  • Directories – Document Output, Input, Logs, Failures, Watched Folders, etc. Anything in your process or linked DSC that refers to a local or UNC directory should always be set as a configuration parameter.
  • Usernames and Passwords – Any secure environment should change important passwords regularly. Consequently, these should never be hard-coded in any application.
  • External URI’s, Web Service endpoints, etc. – Any external calls that are not internal to the application should be a configuration parameter.

How do I implement a configuration parameter?

During development you can elect to make any variable a configuration parameter simply by selecting the Configuration parameter radio button when you create a new variable in Workbench:

Example Configuration Variable

Example Configuration Parameter

When you select the Configuration parameter radio button, you will notice a few things happen. Enduser UI Items section disappears, meaning you can no longer search or interact with the variable in Livecycle Workspace. Also, and more importantly, your available variable Type list becomes smaller. The only types available for a configuration parameter are:

  • Boolean
  • Integer
  • Short
  • String
  • Long

Setting a Default Value is highly recommended during development so you don’t need to constantly open AdminUI and set the parameter properties after you deploy the application.

Likewise, it is recommended to set a descriptive Title parameter as this is the text that will appear in the AdminUI page. If you don’t use a Title the Name of your variable will appear (strOuputDirectory in this case). As a competent developer you are already supplying adequate variable Titles and Descriptions in all of you applications anyway …right?

Once you have created the configuration parameter, you use it as you would any other variable you create in your processes. Updating the variable during the process does not change the default setting in the application.

For example:

Using the Configuration Parameter

Using the Configuration Parameter

To modify the Configuration parameter once you have deployed the application is easy. Just log in to the LiveCycle AdminUI and browse to the Application and the Process you created the variable in:

Changing configuration parameters in AdminUI

Changing configuration parameters in AdminUI

Now whenever you update the configuration parameter via the AdminUI, your application will automatically use the new value for strOutputDirectory and change the location of where your PDF’s are saved. All without opening the application, finding where the path is used, modifying all instances of the path, redeploying and testing.

Stay tuned for Part 2 – I will describe a practical way to organise your configuration parameters within an application you might create in the enterprise.

aemblog

Everything AEM aka CQ5 based on my experience listed here.

Adobe AEM The Right Way

Best practices, tips, and tricks for your Adobe AEM project

/home/bkondepudi

A WCM journey with Day/Adobe CQ

Technoracle (a.k.a. "Duane's World")

A multi-purpose toolkit for the Adobe LiveCycle and AEM Forms developer.

Adobe LiveCycle Blog

A multi-purpose toolkit for the Adobe LiveCycle and AEM Forms developer.

A multi-purpose toolkit for the Adobe LiveCycle and AEM Forms developer.

XFA@Mobile

A multi-purpose toolkit for the Adobe LiveCycle and AEM Forms developer.

Code Monkey

Ramblings of a Developer