Eclipse Project Explorer filter for XML files - eclipse

I have many XML files in the workbench Project Explorer, each one an instance of one of ten different ecore models. For each ecore model I would like to contribute a commonFilter to the navigator's navigatorContent extension point to enable the user to show or hide the corresponding XML files. These are external tool files so there is not a way to identify the content merely by observing the file name or the xml extension, and renaming is not feasible. Using perhaps a class deriving from org.eclipse.jface.viewers.ViewerFilter, what is the best way to identify which of the ecore models the XML file contains? I presume there is a simple way to do this with EMF resources, or with EcoreUtil, or with adapters, but I haven't found a successful technique. Alternatively, a way to do this directly from the extension point's filterExpression or the viewer's viewerContentBinding would be fine. All of the genmodel-derived plugins are available for the various ecore models.
package com.my.navigator;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
public class MyViewerFilter extends ViewerFilter {
public MyViewerFilter() {
}
#Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if ( element instanceof IFile ) {
IFile file = (IFile)element;
// check whether file is one of our ecore models...
// ...
}
return true;
}
}

You could use the org.eclipse.core.contenttype.contentTypes to define new content types for your file.
Use the describer argument of the content type definition to specify a 'content describer' class which can check that the XML file meets your requirements. There is already an XMLContentDescriber class that you can use as a basis for the describer.
For example this is the content type definition for Ant build.xml files:
<extension
point="org.eclipse.core.contenttype.contentTypes">
<content-type
id="antBuildFile"
name="%antBuildFileContentType.name"
base-type="org.eclipse.core.runtime.xml"
file-names="build.xml"
file-extensions="macrodef,ent,xml,ant"
priority="normal">
<describer
class="org.eclipse.ant.internal.core.contentDescriber.AntBuildfileContentDescriber">
</describer>
</content-type>
</extension>
and this is the Ant content describer to give you a rough idea of what you can:
public final class AntBuildfileContentDescriber extends XMLContentDescriber implements IExecutableExtension {
private int checkCriteria(InputSource contents) throws IOException {
AntHandler antHandler = new AntHandler();
try {
if (!antHandler.parseContents(contents)) {
return INDETERMINATE;
}
}
catch (SAXException e) {
// we may be handed any kind of contents... it is normal we fail to parse
return INDETERMINATE;
}
catch (ParserConfigurationException e) {
// some bad thing happened - force this describer to be disabled
String message = "Internal Error: XML parser configuration error during content description for Ant buildfiles"; //$NON-NLS-1$
throw new RuntimeException(message);
}
// Check to see if we matched our criteria.
if (antHandler.hasRootProjectElement()) {
if (antHandler.hasProjectDefaultAttribute() || antHandler.hasTargetElement() || antHandler.hasAntElement()) {
// project and default attribute or project and target element(s)
// or project and top level ant element(s) (classpath, import, macrodef, path, property, taskdef, typedef)
return VALID;
}
// only a top level project element...maybe an Ant buildfile
return INDETERMINATE;
}
return INDETERMINATE;
}
#Override
public int describe(InputStream contents, IContentDescription description) throws IOException {
// call the basic XML describer to do basic recognition
if (super.describe(contents, description) == INVALID) {
return INVALID;
}
// super.describe will have consumed some chars, need to rewind
contents.reset();
// Check to see if we matched our criteria.
return checkCriteria(new InputSource(contents));
}
#Override
public int describe(Reader contents, IContentDescription description) throws IOException {
// call the basic XML describer to do basic recognition
if (super.describe(contents, description) == INVALID) {
return INVALID;
}
// super.describe will have consumed some chars, need to rewind
contents.reset();
// Check to see if we matched our criteria.
return checkCriteria(new InputSource(contents));
}
#Override
public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException {
// do nothing
}
}

Related

How can I add language setting entries to existing CDT eclipse projects?

I am following the steps found here to try to add build settings to files in existing Eclipse CDT projects using the LanguageSettingsProvider extension point, but my settings provider doesn't seem to show in the UI, and its methods aren't queried for settings.
I previously succeeded in adding settings to a project using an external settings provider, but I couldn't find a way to add file-specific settings.
I have implemented a subclass of LanguageSettingsSerializableProvider (let's call it MyProvider), and added it to my plugin.xml thus:
<extension
point="org.eclipse.cdt.core.LanguageSettingsProvider">
<provider
class="com.example.MyProvider"
id="MyProvider_id"
name="I would like to see this in the UI">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
</extension>
The class is implemented approximately thus:
public class MyProvider
extends LanguageSettingsSerializableProvider
implements ILanguageSettingsProvider,
IResourceChangeListener,
ILanguageSettingsEditableProvider,
ILanguageSettingsBroadcastingProvider {
/** The ID of this settings provider */
public static final String MY_PROVIDER_ID = "MyProvider_id"; //$NON-NLS-
/**
* Constructor. Initialises super class with appropriate values.
*/
public MyProvider() {
super( MY_PROVIDER_ID , Messages.UiLabel );
}
#Override
public String getId() {
return MY_PROVIDER_ID ;
}
#Override
public String getName() {
return Messages.UiLabel;
}
#Override
public List<ICLanguageSettingEntry> getSettingEntries(ICConfigurationDescription cfgDescription, IResource resource, String languageId) {
//breakpoint on this line that never gets hit...
return super.getSettingEntries( cfgDescription, resource, languageId );
}
...
}
The real implementation contains some other logic to actually create the settings entries, including registering itself as a resource change listener. The resourceChanged code works fine, calls setSettingsEntries, and then serializeSettings. However, getSettingEntries is never called to obtain these settings.
Is there something I'm missing?
My guess is the plugin.xml is lacking something, but I'm not sure what. There are paragraphs of guidance in the various interfaces that the class implements, but one simple working example would be worth more than a thousand words. I've tried looking at the xml for the built-in settings providers (e.g. GCCBuiltinCompilerSettingsMinGW), but they're defined alongside a lot of other parts of CDT, and it's hard to tell which bits are relevant to my use case.
What I ended up doing was:
someMethod {
final IProject myProject = getProjectFromSomewhere();
final ICProjectDescription projDesc = CoreModel.getDefault().getProjectDescription( myProject );
for (ICConfigurationDescription config : projDesc.getConfigurations()) {
try {
ensureMySettingsProvidedFor( (ILanguageSettingsProvidersKeeper) config );
} catch (ClassCastException e) {
logger.log( Level.WARNING, "Unexpected class was not a keeper of language settings:" + config.getClass().getName(), e );
}
}
}
/**
* Will ensure my settings provider is registered as a settings provider for...
* #param settingsKeeper ...the given configuration.
*/
public static void ensureMySettingsProvidedFor(final ILanguageSettingsProvidersKeeper settingsKeeper) {
if (settingsKeeper instanceof CConfigurationDescriptionCache) {
logger.log(Level.SEVERE, "Got non-writable cached settings. We can't update this!! "
+ "How do we get a writeable version?");
return;
}
for ( ILanguageSettingsProvider provider : settingsKeeper.getLanguageSettingProviders() ) {
if (MyProvider.MY_PROVIDER_ID.equals( provider.getId() )) {
return;
}
}
addMyProvider( settingsKeeper );
}
/**
* Adds my language settings provider to the given configuration by means of its ID.
* #param settingsKeeper The existing configuration.
*/
private static void addMyProvider( final ILanguageSettingsProvidersKeeper settingsKeeper ) {
List<String> ids = new ArrayList<String>();
for ( ILanguageSettingsProvider provider : settingsKeeper.getLanguageSettingProviders() ) {
ids.add( provider.getId() );
}
ids.add(MyProvider.MY_PROVIDER_ID);
List<ILanguageSettingsProvider> newProviders = LanguageSettingsManager.createLanguageSettingsProviders( ids.toArray( new String[ids.size()] ) );
settingsKeeper.setLanguageSettingProviders(newProviders);
}
It doesn't feel like the best answer, but it seems to work most of the time.
One problem is knowing when to do this such that it happens for all projects that don't yet have the provider, but doesn't get called repeatedly, or too often.
Another problem is that we sometimes get a CConfigurationDescriptionCache, and then the code can't do anything.
I'm open to better solutions.

How to read a specific language.properties file?

Here's my problem. I need to generate PDF in particular language chosen by user. Some informations are in language.properties files and I cannot manage to read other files than the current site language.
For example current language is Spanish and User select German. I'd like to read language_de.properties.
I've tried to use:
String Lang=LanguageUtil.get(LanguageUtil.getLocale('de'), "Mykey");
but without sucess, it always returns "Mykey"
If I use :
String Lang=LanguageUtil.get(HttpServletRequest, "Mykey");
It works, but It's the site language and not the one I want.
Any Ideas?
One option is that you have forgotten to define de_DE in your portal-ext.properties for locales.enabled:
#
# Specify the locales that are enabled by default.
#
locales.enabled=en_US,de_DE,es_ES
Another possibility is that the locale is not enabled for your portal instance. You should check that in the admin UI of your instance.
In both cases LanguageUtil.getLocale('de') will return null - and this will return the given key from LanguageUtil.get. You can verify that by printing the result of LanguageUtil.getLocale('de') and LanguageUtil.getLocale('de_DE') (should both be null). Just add the locale to the enabled ones and you are good.
A third option applies, if you have defined the messages in the resource bundle of your portlet (usually you define the messages in a hook or OSGI bundle to use them in more than one portlet). In that case LanguageUtil.get(Locale, String) doesn't know which portlet you are in and can't access the resource bundle of that portlet. That's the difference to LanguageUtil.get(HttpServletRequest, String), which retrieves the portlet from the request.
In that case you have to retrieve the resource bundle from the config given to your Portlet.init(PortletConfig) method. Or you mimic the implementation of LanguageUtil.get(HttpServletRequest, String) with a locale specific parameter:
public class MyLanguageUtil {
public static String get(HttpServletRequest request, Locale locale, String key) {
if (request == null) {
return key;
}
PortletConfig portletConfig = (PortletConfig) request.getAttribute("javax.portlet.config");
if (portletConfig != null) {
ResourceBundle resourceBundle = portletConfig.getResourceBundle(locale);
if (resourceBundle.containsKey(key)) {
return LanguageUtil.get(resourceBundle, key, key);
}
}
return LanguageUtil.get(locale, key);
}
}
ok got it to work.
I added a class for each language in my module language
import java.util.Enumeration;
import java.util.ResourceBundle;
import org.osgi.service.component.annotations.Component;
import com.liferay.portal.kernel.language.UTF8Control;
#Component(
property = { "language.id=es_ES" },
service = ResourceBundle.class
)
public class EsResourceBundle extends ResourceBundle {
#Override
protected Object handleGetObject(String key) {
return _resourceBundle.getObject(key);
}
#Override
public Enumeration<String> getKeys() {
return _resourceBundle.getKeys();
}
private final ResourceBundle _resourceBundle = ResourceBundle.getBundle(
"content.Language_es_ES", UTF8Control.INSTANCE);}
thanks for help
For those who need this to be a little more generic.
Add a small class to your portlet that accesses the portlets ResourceBundle:
public class [MyPortlet]LanguageUtil {
public static String get (Locale locale, String key) {
ResourceBundle resourceBundle = ResourceBundle.getBundle("content.Language", locale, UTF8Control.INSTANCE);
return LanguageUtil.get(resourceBundle, key);
}
public static String format (Locale locale, String pattern, Object[] arguments) {
ResourceBundle resourceBundle = ResourceBundle.getBundle("content.Language", locale, UTF8Control.INSTANCE);
return LanguageUtil.format(resourceBundle, pattern, arguments);
}
}
and export it with the help of the bnd.bnd file of the portlet like:
Export-Package: [path.to.my.util]
This way it can be used in OSGI modules and regular JAVA classes for example like this:
[MyPortlet]LanguageUtil.get(serviceContext.getLocale(), "my-language-string");

Inter Type Declaration on Compiled Class File

Is it possible to do Inter Type Declarations with AspectJ on Compiled Class Files at Load Time Weaving?
As an example: I compile some Groovy code and want to add fields or methods with IDT.
Update:
Oh my goodness, you do not need reflection to access members or execute methods. Eclipse shows errors in the editor, but you may just ignore them, the code compiles and runs fine anyway. So the aspect is really much more strightforward and simple:
public aspect LTWAspect {
public static String Application.staticField = "value of static field";
public String Application.normalField = "value of normal field";
public void Application.myMethod() {
System.out.println(normalField);
}
void around() : execution(void Application.main(..)) {
System.out.println("around before");
proceed();
System.out.println("around after");
System.out.println(Application.staticField);
new Application().myMethod();
}
}
Original answer:
Yes, but you have a hen-and-egg problem there, i.e. you cannot just reference the newly introduced fields from your LTW aspect code without reflection. (The last sentence is not true, see update above.) Plus, in order to make your LTW aspect compile, you need the classes to be woven on the project's build path so as to be able to reference them. Example:
Java project
public class Application {
public static void main(String[] args) {
System.out.println("main");
}
}
AspectJ project
import org.aspectj.lang.SoftException;
public aspect LTWAspect {
public static String Application.staticField = "value of static field";
public String Application.normalField = "value of normal field";
public void Application.myMethod() {
try {
System.out.println(Application.class.getDeclaredField("normalField").get(this));
} catch (Exception e) {
throw new SoftException(e);
}
}
void around() : execution(void Application.main(..)) {
System.out.println("around before");
proceed();
System.out.println("around after");
try {
System.out.println(Application.class.getDeclaredField("staticField").get(null));
Application.class.getDeclaredMethod("myMethod", null).invoke(new Application());
} catch (Exception e) {
throw new SoftException(e);
}
}
}
So, e.g. in Eclipse you need to put the Java project on the AspectJ project's build path under "Projects" because only then it can see Java class Application on which you want to declare members. After compilation you just start the Java project and do LTW on the aspect project (don't forget an aop-ajc.xml referencing LTWAspect).
In my example above I declare a static member, a non-static ("normal") member and a non-static method. My advice prints the static member and calls the non-static method, both via reflection. The non-static method then prints the non-static member, again via reflection. This is not nice, but it works and proves the ITD in combination with LTW is possible. There might be a more elegant way, but if so I am unaware of it. (Update: There is a more elegant way: Just ignore the errors marked by Eclipse IDE, see above.)
Program output
around before
main
around after
value of static field
value of normal field

How to programmatically new a java class which implements sepecified interface in eclipse plugin development

Friends,
Now we are developing a eclipse plugin, it contains a action to generated a service interface and it's impl stub.
Now the interface is generated, I want to use eclipse JDT to create a java class which implements sepecified interface, but don't know how.
The info we have:
the interface name, the impl class name, the packagename, the java project contains them.
Thanks in advance for your kindly help.
A quick scan of how the new class wizard does it, it seems that there is no public easy to use API for this. You can have a look at org.eclipse.jdt.ui.wizards.NewTypeWizardPage.createType(IProgressMonitor) method to see how JDT itself creates new classes.
It should be possible to extend the org.eclipse.jdt.ui.wizards.NewTypeWizardPage, so you can leverage the createType() method.
Probably the minimal steps you would have to do is simply generate source content into the correctly placed IFile. ex:
public Object execute(ExecutionEvent event) throws ExecutionException {
final String PACKAGE_PATH = "z.ex/src/z/ex/go";
final String CONTENT = "package z.ex.go;\n"
+ "public class RunAway {\npublic static void main(String[] args) {\n"
+ "System.out.println(\"Run Away\");\n}\n}\n";
final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
final IResource packageResource = root.findMember(PACKAGE_PATH);
if (packageResource instanceof IFolder) {
IFolder packageFolder = (IFolder) packageResource;
final IFile file = packageFolder.getFile("RunAway.java");
try {
if (!file.exists()) {
file.create(new ByteArrayInputStream(CONTENT.getBytes()),
true, new NullProgressMonitor());
} else {
file.setContents(
new ByteArrayInputStream(CONTENT.getBytes()),
IFile.FORCE | IFile.KEEP_HISTORY,
new NullProgressMonitor());
}
} catch (CoreException e) {
e.printStackTrace();
}
}
return null;
}
See AbstractNewClassWizard for a smaller example that is similar to NewTypeWizardPage and uses some of the JDT APIs.
You can use the new class wizard to create classes.
This will prompt the user for the class name, et cetera. You can initialize the values of the wizard page. Below I am setting the source folder only (and tell the wizard that it cannot be changed, thus the second false parameter). You might want to set the interface and possible the package as well.
OpenNewClassWizardAction wizard = new OpenNewClassWizardAction();
wizard.setOpenEditorOnFinish(false);
NewClassWizardPage page = new NewClassWizardPage();
page.setPackageFragmentRoot(sourceFolder, false);
wizard.setConfiguredWizardPage(page);
wizard.run();
return (IType) wizard.getCreatedElement();
Hope that helps!
Create the entire java file using the JDT - AST. First create the AST and then write it to a java file. It might look as hefty work, but its the best one. You will have complete control.

Is there a way to capitalize the first letter of a value of a variable in Eclipse (Helios) code templates

I have a code template with a variable and I would like to capitalize(just the first letter) the value of this variable only in some occurrences. Is there a way to do this?
The template code is as follows - I would like to capitalize Property Name in my function names...
private $$${PropertyName};
${cursor}
public function get${PropertyName}()
{
return $$this->${PropertyName};
}
public function set${PropertyName}($$value)
{
$$this->${PropertyName} = $$value;
}
Please Note: This is a template for use with code templates in the IDE (not in PHP). For details see: http://www.ibm.com/developerworks/opensource/tutorials/os-eclipse-code-templates/index.html
I also want this and tried to build a custom TemplateVariableResolver to do it. (I already have one custom resolver in place that generates new UUIDs a la http://dev.eclipse.org/blogs/jdtui/2007/12/04/text-templates-2/.)
I made a custom resolver bound to capitalize:
public class CapitalizingVariableResolver extends TemplateVariableResolver {
#Override
public void resolve(TemplateVariable variable, TemplateContext context) {
#SuppressWarnings("unchecked")
final List<String> params = variable.getVariableType().getParams();
if (params.isEmpty())
return;
final String currentValue = context.getVariable(params.get(0));
if (currentValue == null || currentValue.length() == 0)
return;
variable.setValue(currentValue.substring(0, 1).toUpperCase() + currentValue.substring(1));
}
}
(plugin.xml:)
<extension point="org.eclipse.ui.editors.templates">
<resolver
class="com.foo.CapitalizingVariableResolver"
contextTypeId="java"
description="Resolves to the value of the variable named by the first argument, but with its first letter capitalized."
name="capitalized"
type="capitalize">
</resolver>
</extension>
that I would use like this: (I am working in Java; I see that you do not appear to be)
public PropertyAccessor<${propertyType}> ${property:field}() {
return ${property};
}
public ${propertyType} get${capitalizedProperty:capitalize(property)}() {
return ${property}.get();
}
public void set${capitalizedProperty}(${propertyType} ${property}) {
this.${property}.set(${property});
}
As of Eclipse 3.5, the problem I am having is that my custom resolver does not get a chance to re-resolve once I've specified a value for the property variable. It appears that the Java Development Tools (Eclipse JDT) do this dependent template variable re-resolution via a mechanism called MultiVariableGuess within the JavaContext (see addDependency()). Unfortunately for us, that mechanism does not seem to be exposed, so I/we can't use it to do the same (without lots of copy-and-paste or other redundant work).
At this point, I am giving up again for a while and will keep typing the leading-lowercase and leading-uppercase names separately into two independent template variables.