+ Start a Discussion
dev_jhdev_jh 

Eclipse deployment question

Hi all,

We are using Eclipse to migrate metadata between SF organizations and we have checked the documentation available on:

http://wiki.apexdevnet.com/index.php/An_Introduction_to_Force_IDE

Are there any more documents that talk about the FORCE IDE?

We are also wandering if we are using this tool in the best way. We always develop in our Sandbox environment and deploy to production once everything is tested. We do periodic maintenance releases on a bi-weekly or monthly basis. We have created 2 Salesforce Projects, one for the Production System and one for the Sandbox and we have, in both, subscribed to all metadata, as our maintenance releases have a variety of changes (triggers, classes, custom objects, fields, etc... depending).

Is this the right approach? Would it be better to have one project per release and only subscribe to what is changed in that release?

Any help from anyone that has been using this great tool for a while much appreciated. All the best,

J
JonPJonP
Hi J,

The most extensive documentation on the Force.com IDE is in Eclipse online help, after you install the plug-in.  (If help won't open, try this fix.)

Generally we recommend against creating Force.com projects directly against a production organization.  Instead, we strongly recommend using the Force.com > Deploy to Server feature, which allows you to deploy a set of metadata changes easily, in a single transaction.

When you're using a Force.com project for development, against a Sandbox or Developer Edition organization, it's fairly arbitrary what server components you should download into your project.  Generally development in the IDE focuses on Apex code, since most users find working in the web UI easier than editing XML for things like page layouts, tabs, etc.

But when it's time to deploy, the best practice is to create a new Force.com project and use the "Select metadata components" option to hand-pick precisely which components you want to deploy.  This is particularly valuable if you want to deploy partial components, such as a subset of custom fields on a custom object--you will get a .object file either way, but its contents will change based on what you selected. Once you've created the deployment project, you can use the Force.com > Deploy to Server command to launch the deploy wizard, but it's simpler than using your general development project because you already know that the Deployment Plan (step 3) will include everything in your project.  (And if you missed a dependency or otherwise need to change the set of files to deploy, you can always use the Force.com > Add/Remove Metadata Components command to change what's in the project and then relaunch the deploy wizard.)

This best practice is particularly valuable when using a multi-environment deploy process.  If you are testing deployment to a staging sandbox, the test is only valid if you can perform an identical deployment to production.  A separate Force.com project for deployment means it's reusable when you're ready to go live.

If others have come up with their own best practices, it would be great if they could post them.  We build our products expecting them to be used in certain ways, but especially with something as open-ended as an IDE, it's always interesting to learn how our customers have gone above and beyond.

Jon
salesforce.com Product Manager
dev_jhdev_jh
Hi Jon,

Thanks for the detailed response, it is much clearer now, we will take a look at the online help for more detailed documentation.

A couple of questions:

1) We just faced an interesting issue. We made a change on the Opportunity Name standard field to make it a text field instead of an autonumeric one. As part of the changes we also modified the page layout and created some triggers and Appex Classes that update this field. When deploying, because we don´t specify the order of the deployment, we get some errors stating that the trigger is performing an update on a field that can´t be updated. Of course we can do the deployment in steps, deploying first the object and then the rest but, is there a way to specify the deployment order to get it all in one go?

2) It seems that you get a copy of all metadata that you select for a project locally (in the Eclipse folder structure). This could be useful to take periodic Metadata snapshots in case you ever need to revert a change or you want to see how the metadata was set up at a specific date. I know there are tools in the Apexchange to get this done, but this sounds like a free way of doing it! Does this make sense? Is there a better freely available tool to perform this more easily?

Thanks again,

J
JonPJonP
#1 just sounds like a bug or "opportunity for improvement" in the metadata deployment, unless there's something more subtle going on that isn't be surfaced clearly.  We'll look into it.  But for the time being, it sounds like a two-step deployment is the best workaround.

For #2, there is definitely value in using metadata files to capture the state of your organization configuration at a point in time, especially when combined with a version control system like CVS (which Eclipse natively supports), Subversion (get the Subclipse plug-in), or any number of other free or commercial apps.  Eclipse's version control integration features allow you to compare different historical versions of a file so you can see exactly what's changed.  Of course, this means you're looking at raw XML diffs, whereas commercial products like DreamFactory's SnapShot provide a friendlier interface particulary well suited for non-programmers.

Jon
dev_jhdev_jh
Thanks Jon,

Regarding the Opportunity for Improvement or bug just a further note (by the way, for some reason I mentioned this was on a field in Opportunity but it is in fact a Name field, standard therefore, of a Custom object). Strangely enough, we tried sending the object first, as deployment step 1 but this did not manage to change the Production´s field type from autonumber to text. How strange! (especially as other fields were sent).

We saw no option but to make this change manually in production and then deploy the rest of the changes using Eclipse.

If you need more info to look into this at somepoint in the roadmap, give us a shout, we´ll be more than happy to help.

All the best,

J
JonPJonP
There are more restrictions on what you can do with standard object customizations than custom objects.  For example, in Winter '09 you cannot migrate changes to picklist values on standard fields.  So it looks like the ability to set the Name type on a standard object also is not yet available in the Metadata API.
AKallAKall

Hi JonP,

I have tried the fix that you have suggested for gaining access to Eclipse Online Help, but it still doesn't work. Do you a have any other suggestions?

 

Thanks

JonPJonP
What does Eclipse do when you open the online help?  Are there any exceptions in the Eclipse or IDE logs?
AKallAKall

When I click on the 'Help Contents' icon nothing happens. When I click on the 'Dynamic Help' icon the contents appears but any attempt to access an article fails. The code below is what I found in the log that seems to be associated with my actions.

 

!ENTRY org.eclipse.ui 4 0 2009-02-05 15:08:32.656
!MESSAGE Unhandled event loop exception
!STACK 0
java.lang.ExceptionInInitializerError
    at org.eclipse.equinox.http.jetty.internal.HttpServerManager.updated(HttpServerManager.java:78)
    at org.eclipse.equinox.http.jetty.internal.Activator.startServer(Activator.java:208)
    at org.eclipse.equinox.http.jetty.JettyConfigurator.startServer(JettyConfigurator.java:60)
    at org.eclipse.help.internal.server.WebappManager.start(WebappManager.java:43)
    at org.eclipse.help.internal.base.BaseHelpSystem.ensureWebappRunning(BaseHelpSystem.java:187)
    at org.eclipse.help.internal.base.HelpDisplay.displayHelpURL(HelpDisplay.java:152)
    at org.eclipse.help.internal.base.HelpDisplay.displayHelp(HelpDisplay.java:42)
    at org.eclipse.help.ui.internal.DefaultHelpUI.displayHelp(DefaultHelpUI.java:125)
    at org.eclipse.ui.internal.help.WorkbenchHelpSystem.displayHelp(WorkbenchHelpSystem.java:833)
    at org.eclipse.ui.internal.actions.HelpContentsAction$1.run(HelpContentsAction.java:83)
    at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:67)
    at org.eclipse.ui.internal.actions.HelpContentsAction.run(HelpContentsAction.java:81)
    at org.eclipse.jface.action.Action.runWithEvent(Action.java:498)
    at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:546)
    at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:490)
    at org.eclipse.jface.action.ActionContributionItem$5.handleEvent(ActionContributionItem.java:402)
    at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:938)
    at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3682)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3293)
    at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2389)
    at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2353)
    at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2219)
    at org.eclipse.ui.internal.Workbench$4.run(Workbench.java:466)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:289)
    at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:461)
    at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
    at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:106)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:169)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:106)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:76)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:363)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:176)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:508)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:447)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1173)
Caused by: org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: No suitable Log constructor [Ljava.lang.Class;@159e164 for org.apache.commons.logging.impl.Log4JLogger (Caused by java.lang.NoClassDefFoundError: org/apache/log4j/Category) (Caused by org.apache.commons.logging.LogConfigurationException: No suitable Log constructor [Ljava.lang.Class;@159e164 for org.apache.commons.logging.impl.Log4JLogger (Caused by java.lang.NoClassDefFoundError: org/apache/log4j/Category))
    at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:543)
    at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:235)
    at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:209)
    at org.mortbay.log.LogFactory.getLog(LogFactory.java:28)
    at org.mortbay.util.Container.<clinit>(Container.java:39)
    ... 40 more
Caused by: org.apache.commons.logging.LogConfigurationException: No suitable Log constructor [Ljava.lang.Class;@159e164 for org.apache.commons.logging.impl.Log4JLogger (Caused by java.lang.NoClassDefFoundError: org/apache/log4j/Category)
    at org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFactoryImpl.java:413)
    at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:529)
    ... 44 more
Caused by: java.lang.NoClassDefFoundError: org/apache/log4j/Category
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
    at java.lang.Class.getConstructor0(Unknown Source)
    at java.lang.Class.getConstructor(Unknown Source)
    at org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFactoryImpl.java:410)
    ... 45 more
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Category
    at java.lang.ClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(BundleLoader.java:429)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:369)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:357)
    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:83)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClassInternal(Unknown Source)
    ... 50 more
 

JonPJonP

That exception has always been resolved by the solution described in the FAQ, which is to add the following to your Eclipse command-line parameters or to eclipse.ini:

 

-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

Are you certain you did that correctly?

 

AKallAKall

I tried a couple different ways. Here is an example of where pasted the string you provided to the existing string.

-showsplashorg.eclipse.platform--launcher.XXMaxPermSize 256m-vmargs-Xms40m-Xmx256m-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog