WTP: Consumer Control of Access Rules

From Eclipsepedia

Jump to: navigation, search

Contents

Introduction

Access rules are an important part of declaring and documenting a component's API. This is typically done by marking packages as x-internal in the manifest.mf file, and in some cases, declaring your known "friends" with the x-friend directive. In WTP things should be "friends" only if they are in the same feature-component, according to our defined "build features", and as documented in Subsystems and Features.

This conservative approach is done to be useful to adopters, making clear what is not API (yet), but is problematic for WTP itself, since we still have not evolved all our intended API, so even our own code "violate" our API. Of course, these are not very bad violations for WTP, since we'll be releasing everything "in sync" for at least another release or two.

In the mean time, this approach causes too many warnings in the development environment, so the discouraged access warnings have to be turned off or filtered out ... which means we miss important warnings, where we violate someone else's internal packages.

The Solution

There is a capability in the Eclipse Development environment that we in WTP should take advantage of. While, normally, access rules are defined "from below" by the supplied plugins, there is a capability in the IDE to tweak the access rules "from above" so that we, as consumers, can accept certain risks, but still be informed of other violations.

One easy example is that everything in JST can, for now, pretty safely use anything in WST, even though we would not want to declare the WST methods as API (at least yet). So, JST classes using WST classes is an acceptable risk for WTP.

The Method

To tweak the access rules "from above" there are two methods, modify the build path properties using the provided UI, or, "manually" edited the .classpath file ... the UI method is usually recommended, and the .classpath is a system file, and normally users should not be hand editing those.


The Edit Access Rule UI

Pretty easy once you see where it is.

TweakingAccessRules.jpg


Editing the .classpath file

In some cases, it may be easier to try "hand editing" the .classpath file. It is recommended to use the UI approach at least once, and then once that's working, mimic the changes it made to your .classpath file. The end result would look something similar to the following (this example is from the jst.jsp.ui plugin, which depends on a lot from WST).

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
	<classpathentry kind="src" path="src" />
	<classpathentry kind="con"
		path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.4" />
	<classpathentry kind="con"
		path="org.eclipse.pde.core.requiredPlugins">
		<accessrules>
			<accessrule kind="accessible"
				pattern="org/eclipse/wst/sse/core/**" />
			<accessrule kind="accessible"
				pattern="org/eclipse/wst/xml/core/**" />
			<accessrule kind="accessible"
				pattern="org/eclipse/wst/css/core/**" />
			<accessrule kind="accessible"
				pattern="org/eclipse/wst/html/core/**" />
			<accessrule kind="accessible"
				pattern="org/eclipse/wst/sse/ui/**" />
			<accessrule kind="accessible"
				pattern="org/eclipse/wst/xml/ui/**" />
			<accessrule kind="accessible"
				pattern="org/eclipse/wst/css/ui/**" />
			<accessrule kind="accessible"
				pattern="org/eclipse/wst/html/ui/**" />				
			<accessrule kind="accessible"
				pattern="org/eclipse/wst/javascript/ui/**" />	
			<accessrule kind="accessible"
				pattern="org/eclipse/wst/validation/**" />
			<accessrule kind="accessible"
				pattern="org/eclipse/wst/common/componentcore/internal/util/IModuleConstants" />
		</accessrules>
	</classpathentry>
	<classpathentry kind="output" path="bin" />
</classpath>

Best Practices and Policy in WTP

First, and most important, it would never be appropriate to "hide" discouraged access warnings from any plugins outside of WTP.

Second, it's highly recommended to make the rules as specific as you can ... preferably right down to the specific class or interface. Technically, any JST plugin could simply use a pattern of "org/eclipse/wst/**" but this would not be very informative to others reading your code (and there are others that read your code :), but more important, using the more specific patterns prevents you from making an accidental use of non-api from another plugin. For example, using the JSP UI classpath patterns above, you can see we rely heavily on the other editing components, both UI and core, since this itself is a UI plugin, but we do not depend on many non-API in wst.common.componentcore ... just one Interface, so we list it explicitly. That way if someone should happen to write some code that happened to use another non-api class form wst.common.componentcore, we'd still get a warning about it right away, and make a considered decision if that was the right thing to do, or not. If not, we'd find another way, if worth the (slight) risk, we'd modify the access rules at that time.

Extending to PDE builds

While it is not built in to PDE build, our vast and brilliant release engineering team :) has written the code to tweak the JDT compiler arguments during the build process, based on the .classpath found in the bundle. (so ... be sure your .classpath files are checked into CVS ... which should always be true ... that's nothing new, but not sure it's mattered until now).

This allows the output from our batch builds to be just like our development environment warnings.

Note, at the time of this writing, this batch build tweaking does make some very general assumptions, so we can get "clean" output quickly. If a .classpath contains no custom access rules, we do assume very general rules ... such as anything in WST can use anything else in WST, and anything in JST, JSF, or JPA can use anything in JST or WST. Probably, after teams have time to get used to tweaking their own access rules, we will, probably, remove this general assumption.

The code itself for the ant task, is in the CustomizeAccessRules class in our org.eclipse.wtp.releng.tools project, which is buried in our cvs repository in releng.builder/tools/org.eclipse.wtp.releng.tools.

The ant task is ran during the postGenerate task in our customTargets.xml files. Invoking the task says we want to use our customized access rules, and the defaultRules attribute gives the default pattern to use, if the .classpath contains no access rules at all.

<target name="postGenerate">
    <customizeAccessRules 
                bundleDirectory="${buildDirectory}/plugins" 
                defaultRules="+org/eclipse/wst/**/*, +org/eclipse/jst/**/*" />
</target>

Comments welcome

I think this customization of access rules will help us take advantage of an Eclipse feature that so far we have not been able to use, since there has been too many warnings in our IDE environment to read.

In principle, it should give roughly the same information that is in our API Violation scans. But, the API scans are not quite as built-in to Eclipse as access rule warnings are.

Plus, one thing those API Violation scans do not pick up is the use of non-api constants, since those constants are usually inlined, and our API violation scans are based on byte codes, not source.

Plus, it does seem to list a few things I would have thought the API Scans would have caught ... so, it is a nice redundancy check ... please report any bugs you see (in either scans, or the access rules).