How do I easily query a running Eclipse for its installed Features? - eclipse

I'm building an Eclipse Feature that has a requirement that amounts to this... The Feature must be able to be uninstalled automatically if the user has his license revoked.
If you want more background information about that, Here is another question that I've asked on this topic.
Thanks to the answers on that question, I've been trying to learn the Eclipse p2 director api. I've found some classes that look useful here
I've been trying to instantiate one of these classes in my code, but with no luck yet.
I've been reading the help documentation, and I'm getting kind of lost in it all.
I'm stuck because I have a need to supply the OperationFactory with a collection of IInstallableUnit objects.
private void scheduleUninstallOperationJob(
Collection<? extends IVersionedId> toUninstall)
{
OperationFactory oFactory = new OperationFactory();
Collection<URI> repos = null;
UninstallOperation op = null;
try {
op = oFactory.createUninstallOperation(toUninstall, repos, null);
} catch (ProvisionException e) {
e.printStackTrace();
}
IStatus result = op.resolveModal(null);
if (result.isOK()) {
op.getProvisioningJob(null).schedule();
}
}
I don't see any way to easily ask the running instance of Eclipse to give me the collection of currently installed InstallableUnits so that I can easily pass the one I want to uninstall to the OperationFactory.createUninstallOperation() method.
I've tried using Eclipse source code as an example, but the code that I have found is the org.eclipse.equinox.p2.ui.ProvisioningUI, and it's tightly coupled to the UI that is used when manually uninstalling InstallableUnits. This code also uses code that is in the dreaded Eclipse internal packages which I would like to avoid using if possible.
Thank you for your consideration, Trace

This code gets the collection of IUs which are managed by the profile of the currently running system:
/**
* This Activator informs user about the IUs which are currently installed in
* the running environment.
*
* This code is intended for demo only and should be much more defensive for
* production use.
*
* #author Ilya Shinkarenko
*
*/
public class SelfInformerActivator extends Plugin {
#Override
public void start(final BundleContext ctx) throws Exception {
super.start(ctx);
ServiceReference<IProvisioningAgentProvider> sr = ctx.getServiceReference(IProvisioningAgentProvider.class);
IProvisioningAgentProvider agentProvider = ctx.getService(sr);
URI p2InstanceURI = null; // myself
final IProvisioningAgent agent = agentProvider.createAgent(p2InstanceURI);
IProfileRegistry regProfile = (IProfileRegistry) agent.getService(IProfileRegistry.SERVICE_NAME);
IProfile profileSelf = regProfile.getProfile(IProfileRegistry.SELF);
IQuery<IInstallableUnit> query = QueryUtil.createIUAnyQuery();
//This is what you need:
IQueryResult<IInstallableUnit> allIUs = profileSelf.query(query, new NullProgressMonitor());
//Let's output it:
Iterator<IInstallableUnit> iterator = allIUs.iterator();
while (iterator.hasNext()) {
IInstallableUnit iu = iterator.next();
System.out.println(iu);
}
}
}

There was very little traffic on this question. I attribute that to the odd nature of the requirement that is driving this development.
Well, it seems that those requirements have changed, and I will no longer be needing to programmatically uninstall Eclipse Features based on a revoked license. Therefore I will stop researching how to do this for now.
If you're looking to solve this issue to, feel free to contact me by leaving a comment here, or answering this question with another question. :)

Related

How to customize addContentItemDialog to restrict files over 10mb upload in IBM Content Navigator

I am customizing ICN (IBM Content Navigator) 2.0.3 and my requirement is to restrict user to upload files over 10mb and only allowed files are .pdf or .docx.
I know I have to extend / customize the AddContentItemDialog but there is very less detail on exactly how to do it, or any video on it. I'd appreciate if someone could guide.
Thanks
I installed the development environment but I am not sure how to extend the AddContentItemDialog.
public void applicationInit(HttpServletRequest request,
PluginServiceCallbacks callbacks) throws Exception {
}
I want to also know how to roll out the changes to ICN.
This can be easily extended. I would suggest to read the ICN red book for the details on how to do it. But it is pretty standard code.
Regarding rollout the code to ICN, there are two ways:
- If you are using plugin: just replace the Jar file on the server location and restart WAS.
- If you are using EDS: you need to redeploy the web service and restart WAS.
Hope this helps.
thanks
Although there are many ways to do this, one way indeed is tot extend, or augment the AddContentItemDialog as you qouted. After looking at the (rather poor IBM documentation) i figured you could probably use the onAdd event/method
Dojo/Aspect#around allows you to do exactly that, example:
require(["dojo/aspect", "ecm/widget/dialog/AddContentItemDialog"], function(aspect, AddContentItemDialog) {
aspect.around(AddContentItemDialog.prototype, "onAdd", function advisor(original) {
return function around() {
var files = this.addContentItemGeneralPane.getFileInputFiles();
var containsInvalidFiles = dojo.some(files, function isInvalid(file) {
var fileName = file.name.toLowerCase();
var extensionOK = fileName.endsWith(".pdf") || fileName.endsWith(".docx");
var fileSizeOK = file.size <= 10 * 1024 * 1024;
return !(extensionOK && fileSizeOK);
});
if (containsInvalidFiles) {
alert("You can't add that :)");
}else{
original.apply(this, arguments);
}
}
});
});
Just make sure this code gets executed before the actual dialog is opened. The best way to achieve this, is by wrapping this code in a new plugin.
Now on creating/deploying plugins -> The easiest way is this wizard for Eclipse (see also a repackaged version for newer eclipse versions). Just create a new arbitrary plugin, and paste this javascript code in the generated .js file.
Additionally it might be good to note that you're only limiting "this specific dialog" to upload specific files. It would probably be a good idea to also create a requestFilter to limit all possible uses of the addContent api...

Why is my update in my plugin on my custom entity not occurring?

I'm writing an auto number plugin for MS Dynamics CRM 2015. It works on the creation of an opportunity, when a new number needs to be generated. The current number is stored in another entity, which is retrieved at the time of creating the opportunity and then adds 1. The auto number entity is then updated with the new number (except it isn't as this isn't working at the moment).
At the moment the number is retrieved and 1 is added to it and is used in the opportunity correctly. However, as the update to the auto number entity does not occur when another opportunity is created it gets the same number as the previous one.
Here's my plugin code so far:
protected void ExecuteGenerateOpportunityAutoNumber(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName == OPPORTUNITY_ENTITY_NAME)
{
if (!entity.Attributes.Contains(OPPORTUNITY_REF_ID))
{
try
{
string newId = RetrieveAndUpdateLastId(service);
entity.Attributes.Add(OPPORTUNITY_REF_ID, newId);
}
catch (FaultException ex)
{
throw new InvalidPluginExecutionException("GenerateOpportunityAutoNumber plugin error: ", ex);
//tracingService.Trace("GenerateOpportunityAutoNumber plugin error: {0}", ex.Message);
}
}
}
}
}
The RetrieveAndUpdateLastId method code is below:
private string RetrieveAndUpdateLastId(IOrganizationService service)
{
lock (lastIdentifierLock)
{
string result = null;
ColumnSet cols = new ColumnSet();
cols.AddColumns(LAST_REF_LAST_VALUE, LAST_REF_PRIMARY_KEY);
QueryExpression query = new QueryExpression();
query.ColumnSet = cols;
query.EntityName = LAST_REF_ENTITY_NAME;
EntityCollection ec = service.RetrieveMultiple(query);
if (ec.Entities.Count >= 1)
{
foreach (Entity identifier in ec.Entities)
{
if (identifier.Attributes.Contains(LAST_REF_LAST_VALUE))
{
int? lastValue = identifier[LAST_REF_LAST_VALUE] as int?;
if (lastValue != null)
{
string newValue = (lastValue.Value + 1).ToString().PadLeft(7, '0');
result = String.Format("SN{0}", newValue); //This is clearly happening as I'm getting the next number back.
identifier[LAST_REF_LAST_VALUE] = lastValue.Value + 1;
//Tried this also:
//identifier.Attributes.Remove(LAST_REF_LAST_VALUE);
//identifier.Attributes.Add(LAST_REF_LAST_VALUE, lastValue.Value + 1);
service.Update(identifier); //This doesn't seem to be happening.
break;
}
}
}
}
return result;
}
}
No error is thrown but the update of the auto number just isn't happening. I've checked the user I'm running this as has the required update privileges on the auto number entity as well. Any ideas?
UPDATE
After debugging I found that it was throwing an error that the Principal user is missing the prvWrite privilege. This would explain why the update isn't happening, but now raises another issue. I've setup the plugin to run as a specific user (one with the correct privileges), but the Guid of the 'Principal user' in the error was of the calling user. Why would it run as the calling user when I've set it up to use a specific user?
UPDATE 2
I think I may have found the issue but wonder if anyone else can confirm / shed some more light on this. It seems that according to this, the issue may lie with the user not being in a specific AD group, specifically
User account (A) needs the privilege prvActOnBehalfOfAnotherUser,
which is included in the Delegate role.
Alternately, for Active Directory directory service deployments only,
user account (A) under which the impersonation code is to run can be
added to the PrivUserGroup group in Active Directory. This group is
created by Microsoft Dynamics CRM during installation and setup. User
account (A) does not have to be associated with a licensed Microsoft
Dynamics CRM user. However, the user who is being impersonated (B)
must be a licensed Microsoft Dynamics CRM user.
For my purposes I think the user I'm trying to run as needs to be in PrivUserGroup in AD (which it's not), otherwise it defaults to the calling user.
UPDATE 3
I've been able to identify 2 fundamental problems. The first is as explained above, in that the context always runs as the calling user. The 2nd is that when either giving the calling user system admin privileges OR creating the IOrganizationService with a null parameter it still doesn't update. HOWEVER, and this seems very odd, these 2 scenarios DO work when profiling the plugin. Why would this be?
UPDATE 4
It seems I may have resolved the issue, though I'm not certain (hence why I've not written an answer as yet). As per the documentation we've added the user to be impersonated into the PrivUserGroup. The plugin now works. However, I don't understand why this is needed. Also, is this best practice in this scenario or have I done something that should never be done?
On a related note I also unregistered the plugin before deploying it this time, so I'm now wondering if this solved this issue. To confirm I've now removed the user from the PrivUserGroup in AD, but this takes some time (not sure exactly how long) to filter through apparently. If it still works then it looks like this actually resolved it. Do you normally need to unregister a plugin before re-deploying it to make sure it works?
UPDATE 5
Ok, so this if my final update. I'm not marking this as the answer as I'm not 100% certain, but it appears that removing the assembly using the plugin registration tool may have done the trick. From everything I've read you shouldn't need to unregister a plugin to redeploy, so my perhaps my assembly was corrupt somehow and by removing it and creating it again using the new assembly solve the issue. Unfortunately I don't have the original assembly to test with.
I would suggest to debug your plugin. Following article contains a video that describes how to debug plugins using Plugin Debugger and Plugin Regitration Tool - http://blogs.msdn.com/b/devkeydet/archive/2015/02/17/debug-crm-online-plugins.aspx
Updated How to have 2 instances of IOrganizationService for user context and system:
Open Plugin.cs file.
Locate following code:
internal IOrganizationService OrganizationService
{
get;
private set;
}
Add following code after:
internal IOrganizationService SystemOrganizationService
{
get;
private set;
}
Find following code:
// Use the factory to generate the Organization Service.
this.OrganizationService = factory.CreateOrganizationService(this.PluginExecutionContext.UserId);
Add following code after:
this.SystemOrganizationService = factory.CreateOrganizationService(null);
Use this instance of IOrganizationService in the place where you need higher level of privileges.

Eclipse Plugin Development - Getting information from Team Provider

I am very new to developing eclipse plugins. The biggest hurdle I am facing right now is where/how to get at the data from various other plugins. I am having a real hard time finding documentation for this. For instance the Team Provider plugin....
How do I read the svn revision of a file? Lets say I have an IResourceChangeListener and I want to keep track of the svn revision number of a file (if the user did an update for example).
If I want to ask svn if there are pending updates for a project, how do I talk to the eclipse team provider?
I am not sure where to start...
Thanks!
I eventually discovered what I was looking for after many hours of searching. Unfortunately since I have less than 100 rep. I have been unable to post until now....
I am making a little progress on this. I randomly stumbled upon this while pouring through eclipse source code.
The following code snippet monitors everything that goes on with regard to an svn enabled project. If you save a file, to an update, revert etc. Anything that touches the files or meta data of the files. I just print out the file/direcory name and its revision number.
Subversive version:
final Subscriber subscriber = UpdateSubscriber.instance();
subscriber.addListener(new ISubscriberChangeListener() {
#Override
public void subscriberResourceChanged(ISubscriberChangeEvent[] events) {
for(ISubscriberChangeEvent event : events) {
UpdateSyncInfo info = (UpdateSyncInfo) subscriber.getSyncInfo(event.getResource());
System.out.println(event.getResource().getName()+" revision: "+uInfo.getLocalResource().getRevision());
}
}
});
The real trick was figuring out the entry point to get at this information: UpdateSubscriber. It would be nice if there was a good resource for finding out this sort of information.
Subclipse version:
private static final Subscriber subscriber = SVNWorkspaceSubscriber.getInstance();
private static final ISubscriberChangeListener subsciberListener = new ISubscriberChangeListener() {
#Override
public void subscriberResourceChanged(ISubscriberChangeEvent[] events) {
try {
for (ISubscriberChangeEvent event : events) {
SVNStatusSyncInfo info = (SVNStatusSyncInfo) subscriber.getSyncInfo(event.getResource());
System.out.println(event.getResource().getName() + " revision: " + info.getRepositoryRevision());
}
} catch (TeamException e) {
}
}
};
#Override
public void start(BundleContext context) throws Exception {
super.start(context);
subscriber.addListener(subsciberListener);
}
#Override
public void stop(BundleContext context) throws Exception {
subscriber.removeListener(subsciberListener);
super.stop(context);
}
For general information on the Team API in the Eclipse platform, review the documentation in the help system.
http://help.eclipse.org/helios/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/team.htm
(If you're working with the Subscriber stuff, it appears that's mentioned under the "Synchronization Support" -> "Beyond the Basics" topic.)
The Java doc for the team packages also helps:
http://help.eclipse.org/helios/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/api/org/eclipse/team/core/package-summary.html
If you're trying to integrate with or otherwise extend the Subclipse or Subversive team providers, you may have better luck asking your question in their forums:
http://subclipse.tigris.org/ds/viewForums.do
http://www.eclipse.org/subversive/newsgroup.php
One starting point would be to explore the sources of subversive to see how they did their implementation of the features you are describing.
The sources for eclipse.team (the common module for all VCS plugins) are available in a Git repo.
The sources for EGit, another VCS plugin (for Git) can also be instructive.

NUnit extension

Hi All i have a question regarding NUnit Extension (2.5.10).
What i am trying to do is write some additional test info to the
database. For that i have created NUnit extension using Event
Listeners.
The problem i am experiencing is that public void
TestFinished(TestResult result) method is being called twice at
runtime. And my code which writes to the database is in this method
and that leaves me with duplicate entries in the database. The
question is: Is that the expected behaviour? Can i do something about
it?
The extension code is below. Thanks.
using System;
using NUnit.Core;
using NUnit.Core.Extensibility;
namespace NuinitExtension
{
[NUnitAddinAttribute(Type = ExtensionType.Core,
Name = "Database Addin",
Description = "Writes test results to the database.")]
public class MyNunitExtension : IAddin, EventListener
{
public bool Install(IExtensionHost host)
{
IExtensionPoint listeners = host.GetExtensionPoint("EventListeners");
if (listeners == null)
return false;
listeners.Install(this);
return true;
}
public void RunStarted(string name, int testCount){}
public void RunFinished(TestResult result){}
public void RunFinished(Exception exception){}
public void TestStarted(TestName testName){}
public void TestFinished(TestResult result)
{
// this is just sample data
SqlHelper.SqlConnectAndWRiteToDatabase("test", test",
2.0, DateTime.Now);
}
public void SuiteStarted(TestName testName){}
public void SuiteFinished(TestResult result){}
public void UnhandledException(Exception exception){}
public void TestOutput(TestOutput testOutput){}
}
}
I have managed to fix the issue by simply removing my extension
assembly from NUnit 2.5.10\bin\net-2.0\addins folder. At the moment
everything works as expected but i am not sure how. I thought that you
have to have the extension/addin assembly inside the addins folder.
I am running tests by opening a solution via NUnit.exe. My extension
project is part of the solution i am testing. I have also raised this issue with NUnit guys and got the following explanation:
Most likely, your addin was being loaded twice. In order to make it easier to test addins, NUnit searches each test assembly for addins to be loaded, in addition to searching the addins directory. Normally, when you are confident that your addin works, you should remove it from the test assembly and install it in the addins folder. This makes it available to all tests that are run using NUnit. OTOH, if you really only want the addin to apply for a certain project, then you can leave it in the test assembly and not install it as a permanent addin.
http://groups.google.com/group/nunit-discuss/browse_thread/thread/c9329129fd803cb2/47672f15e7cc05d1#47672f15e7cc05d1
Not sure this answer is strictly relevant but might be useful.
I was having a play around with the NUnit library recently to read NUnit tests in so they could easily be transfered over to our own in-house acceptance testing framework.
It turns out we probably wont stick with this but thought it might be useful to share my experiences figuring out how to use the NUnit code:
It is different in that it doesn't get run by the NUnit console or Gui Runner but just by our own console app.
public class NUnitTestReader
{
private TestHarness _testHarness;
public void AddTestsTo(TestHarness testHarness)
{
_testHarness = testHarness;
var package = new TestPackage(Assembly.GetExecutingAssembly().Location){AutoBinPath = true};
CoreExtensions.Host.InitializeService();
var testSuiteBuilder = new TestSuiteBuilder();
var suite = testSuiteBuilder.Build(package);
AddTestsFrom(suite);
}
private void AddTestsFrom(Test node)
{
if (!node.IsSuite)
AddTest(node);
else
{
foreach (Test test in node.Tests)
AddTestsFrom(test);
}
}
private void AddTest(Test node)
{
_testHarness.AddTest(new WrappedNUnitTest(node, TestFilter.Empty));
}
}
The above reads NUnit tests in from the current assembly wraps them up and then adds them to our inhouse test harness. I haven't included these classes but they're not really important to understanding how the NUnit code works.
The really useful bit of information here is the static to "InitialiseService" this took quite a bit of figuring out but is necessary to get the basic set of test readers loaded in NUnit. You need to be a bit careful when looking at the tests in NUnit aswell as it includes failing tests (which I assume dont work because of the number of statics involved) - so what looks like useful documentation is actually misleading.
Aside from that you can then run the tests by implementing EventListener. I was interested in getting a one to one mapping between our tests and NUnit tests so each test is run on it's own. To achieve this you just need to implement TestStarted and TestFinished to do logging:
public void TestStarted(TestName testName)
{
}
public void TestFinished(TestResult result)
{
string text;
if (result.IsFailure)
text = "Failure";
else if (result.IsError)
text = "Error";
else
return;
using (var block = CreateLogBlock(text))
{
LogFailureTo(block);
block.LogString(result.Message);
}
}
There are a couple of problems with this approach: Inherited Test base classes from other assemblies with SetUp methods that delegate to ones in the current assembly dont get called. It also has problems with TestFixtureSetup methods which are only called in NUnit when TestSuites are Run (as opposed to running test methods on their own).
These both seem to be problems with NUnit although if you dont want to construct wrapped tests individually I think you could just put in a call to suite.Run with the appropriate parameters and this will fix the latter problem

Eclipse RCP: How to access internal classes of plugins?

I want to use the default XML editor (org.eclipse.wst.xml.ui) of Eclipse in an RCP application. I need to read the DOM of the xml file currently open. The plugin doesn't offer any extension point, so I'm trying to access the internal classes. I am aware that the I should not access the internal classes, but I don't have another option.
My approach is to create a fragment and an extension point to be able to read data from the plugin. I'm trying not to recompile the plugin, that's why I thought that a fragment was necessary. I just want to load it and extract the data at runtime.
So, my question is: is there another way to access the classes of a plugin? if yes, how?
Any tutorial, doc page or useful link for any of the methods is welcome.
Since nobody answered my question and I found the answer after long searches, I will post the answer for others to use if they bump into this problem.
To access a plugin at runtime you must create and extension point and an extension attached to it into the plugin that you are trying to access.
Adding classes to a plugin using a fragment is not recommended if you want to access those classes from outside of the plugin.
So, the best solution for this is to get the plugin source from the CVS Repository and make the modifications directly into the source of the plugin. Add extension points, extensions and the code for functionality.
Tutorials:
Getting the plugin from the CVS Repository:
http://www.eclipse.org/webtools/community/tutorials/DevelopingWTP/DevelopingWTP.html
Creating extensions and extension points and accessing them:
http://www.vogella.de/articles/EclipseExtensionPoint/article.html
http://www.eclipsezone.com/eclipse/forums/t97608.rhtml
I ended up extending XMLMultiPageEditorPart like this:
public class MultiPageEditor extends XMLMultiPageEditorPart implements
IResourceChangeListener {
#Override
public void resourceChanged(IResourceChangeEvent event) {
// TODO Auto-generated method stub
setActivePage(3);
}
public Document getDOM() {
int activePageIndex = getActivePage();
setActivePage(1);
StructuredTextEditor fTextEditor = (StructuredTextEditor) getSelectedPage();
IDocument document = fTextEditor.getDocumentProvider().getDocument(
fTextEditor.getEditorInput());
IStructuredModel model = StructuredModelManager.getModelManager()
.getExistingModelForRead(document);
Document modelDocument = null;
try {
if (model instanceof IDOMModel) {
// cast the structured model to a DOM Model
modelDocument = (Document) (((IDOMModel) model).getDocument());
}
} finally {
if (model != null) {
model.releaseFromRead();
}
}
setActivePage(activePageIndex);
return modelDocument;
}
}
This is not a clean implementation, but it gets the job done.