Location not being saved to config.yml - bukkit

I'm trying to save a Location in a config.yml, and when he steps onto that location, it provokes an action. However, that is not happening.
Sorry for including the entire code, but I thought it would be essential for this kind of program.
Main class:
public class Turrets extends JavaPlugin{
ArrayList<String> playersThatShouldPlaceBlock = new ArrayList<String>();
HashMap<String, String> turretName = new HashMap<String, String>();
String turretsMsg = ChatColor.RED + "[" + ChatColor.GOLD + "Turrets" + ChatColor.RED + "]" + ChatColor.GOLD + ": ";
public int waitForPlacement;
public void loadConfig() {
this.getConfig().addDefault("Turrets.", null);
this.saveConfig();
}
public void onEnable(){
new CreateTurretEvent(this);
loadConfig();
}
public void onDisable(){
loadConfig();
}
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
final Player p = (Player) sender;
if (cmd.getName().equalsIgnoreCase("turret")){
if (args.length < 2){
p.sendMessage(turretsMsg + ChatColor.RED + "Invalid usage! /turret [create or delete] [name]");
return true;
}
else if (args.length >= 2){
if (args[0].equalsIgnoreCase("create")){
if (args[1] != null){
p.sendMessage(turretsMsg + ChatColor.GOLD + "Place a block and YOU will become a turret when you step on it!");
playersThatShouldPlaceBlock.add(p.getName());
turretName.put(p.getName(), args[1]);
waitForPlacement = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable(){
#Override
public void run() {
p.sendMessage(turretsMsg + ChatColor.RED + "You waited too long so the action was cancelled!");
playersThatShouldPlaceBlock.remove(p.getName());
}
}, 600L);
return true;
}
}
}
}
return false;
}
}
Listener class:
package me.mortadelle2.turrets;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerMoveEvent;
public class CreateTurretEvent implements Listener{
Turrets getter;
public CreateTurretEvent(Turrets plugin){
plugin.getServer().getPluginManager().registerEvents(this, plugin);
getter = plugin;
}
#EventHandler
public void playerPlacesBlockToBecomeTurret(BlockPlaceEvent e){
Player p = e.getPlayer();
if (getter.playersThatShouldPlaceBlock.contains(p.getName())){
p.sendMessage(getter.turretsMsg + "That block is now turretified!");
getter.getServer().getScheduler().cancelTask(getter.waitForPlacement);
getter.playersThatShouldPlaceBlock.remove(p.getName());
Location blockLocation = e.getBlock().getLocation();
getter.getConfig().set("Turrets." + getter.turretName.get(p.getName()), blockLocation);
}
}
#EventHandler
public void playerStepsOnTurret(PlayerMoveEvent e){
Player p = e.getPlayer();
if (getter.getConfig().contains("test")){ //I will add something more specific than test later
p.sendMessage("This is a test");
}
}
}

Problem 1: spelling mistake (this problem has been edited out of the question at question revision 3)
You seem to have misspelled onDisbale(){. When a plugin is disabled, it will run the method onDisable() on your plugin. In your case it isn't run because you don't have a method with that exact signature.
How to prevent this in the future
By added #Override at the start of a method, you are saying that it MUST override a existing method found in a parent class. This can be used like:
#Override
public void onDisable() {
Problem 2: Implementation of the PlayerMoveEvent isn't finished yet
Notice, stackoverflow isn't a "we write code for you service"
By analyzing your code, you are saving your config in the following format:
playername:
turretname: (location object)
Step 1: changing the location saving
The bukkit configuration doesn't work properly with Location objects, you should change your location saving to
getter.getConfig().set("Turrets." + getter.turretName.get(p.getName())+ ".world", player.getLocation().getWorld().getName());
getter.getConfig().set("Turrets." + getter.turretName.get(p.getName())+ ".x", player.getLocation().getBlockX());
getter.getConfig().set("Turrets." + getter.turretName.get(p.getName())+ ".y", player.getLocation().getBlockY());
getter.getConfig().set("Turrets." + getter.turretName.get(p.getName())+ ".z", player.getLocation().getBlockZ());
This changes the configuration to store the world, x, y and z seperately
Step 2: parsing the config at the PlayerMoveEvent
Because we changed our config format, it will be easier to detect what turret we are standing on at the PlayerMoveEvent
We will the following method of detecting what block we are standing on at the PlayerMove
Check if the turret exists inside the configuration
ConfigurationSection sec = getter.getConfig().getConfigurationSection("Turrets."+getter.turretName.get(p.getName()));
// Todo: check if the player exists inside getter.turretName
if(sec != null){
....
}
Parse the configuration to check if the location is found
Location loc = event.getPlayer().getLocation();
if(loc.getBlockX() == sec.getInt("x") && loc.getBlockY() == sec.getInt("y") && loc.getBlockZ() == sec.getInt("z") && loc.getWorld().getName().equals(sec.getString("world"))) {
event.getPlayer().sendMessage("This is a test");
}
This should fix the problem you are having. The following improvements can be done:
Only call the player move code when the player changes the block
Use more descriptive variable names, for example getter should be renamed to main or plugin

Related

Retrying a complete testNG class and not just #Test method on skip/failure

I have implemented IRetryAnalyzer to re-run my failed test cases in my testNG class.
public class Retry implements IRetryAnalyzer {
private int retryCount = 0;
private int maxRetryCount = 1;
private int outcome;
// Below method returns 'true' if the test method has to be retried else 'false'
//and it takes the 'Result' as parameter of the test method that just ran
public boolean retry(ITestResult result) {
//outcome=result.getStatus();
if (retryCount < maxRetryCount ) {
result.getTestContext().getFailedTests().removeResult(result);
result.getTestContext().getSkippedTests().removeResult(result);
System.out.println("Retrying test " + result.getName() + " with status "
+ getResultStatusName(result.getStatus()) + " for the " + (retryCount+1) + " time(s).");
Reporter.log("Retrying test " + result.getName() + " with status "
+ getResultStatusName(result.getStatus()) + " for the " + (retryCount+1) + " time(s).");
retryCount++;
return true;
}
return false;
}
public String getResultStatusName(int status) {
String resultName = null;
if(status==1)
resultName = "SUCCESS";
if(status==2)
resultName = "FAILURE";
if(status==3)
resultName = "SKIP";
return resultName;
}
}
Now I have two Test methods:
#Test(priority = 3, enabled = true, dependsOnMethods={"step2"})
public void step3()
{.....................some code......}
#Test(priority = 4, enabled = true,dependsOnMethods={"step3"})
public void step4() {
....some codee..}
If step 3 fails, testNG skips step 4 which is as expected. But upon re-run it executes only step 3 and even if it passed at second attempt, step 4 which was skipped is not executed.
Is there any way I can re-run my whole TestNG failed class or an alternate solution to run my dependent cases after the #Test method they depend on fails.
Thanks in advance!
Please do the following to get this to work:
Remove the logic of removing failed and skipped tests from your org.testng.IRetryAnalyzer implementation i.e., the below two lines
result.getTestContext().getFailedTests().removeResult(result);
result.getTestContext().getSkippedTests().removeResult(result);
Include this logic of removing the skipped/failed tests from within either an #AfterMethod method (or) from within an afterInvocation() of a org.testng.IInvokedMethodListener listener implementation.
Something like below :
#AfterMethod
public void afterMethod(ITestResult result) {
IRetryAnalyzer retry = result.getMethod().getRetryAnalyzer();
if (retry == null) {
return;
}
result.getTestContext().getFailedTests().removeResult(result.getMethod());
result.getTestContext().getSkippedTests().removeResult(result.getMethod());
}
(or)
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
public class Listener implements IInvokedMethodListener {
#Override
public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
}
#Override
public void afterInvocation(IInvokedMethod method, ITestResult result) {
IRetryAnalyzer retry = result.getMethod().getRetryAnalyzer();
if (retry == null) {
return;
}
result.getTestContext().getFailedTests().removeResult(result.getMethod());
result.getTestContext().getSkippedTests().removeResult(result.getMethod());
}
}
If you leverage the listener path, please ensure that you wire in the listener using one of the following ways :
via #Listeners annotation (or)
via <listeners> tag (or)
via service loaders in TestNG.
For more information refer to my blog post here.
Additing to the Krishnan Mahadevan answer, you can chose to skip
result.getTestContext().getFailedTests().removeResult(result.getMethod());
If you remove a failed test method then, depending on test case (step4) will be executed even when step3 gets fail after retry.

Active Directory notifications

I have seen this example documented by microsoft, but cannot get it to work in visual studio 2012, under a console project.
https://msdn.microsoft.com/en-us/library/ms676877(v=vs.85).aspx
Is there something I am missing, ie. is a console application correct.
The Errors I get are:
Error 1 error LNK2019: unresolved external symbol __imp__ldap_openW referenced in function "int __cdecl GetChangeNotifications(wchar_t *)" (?GetChangeNotifications##YAHPA_W#Z) C:\projects\AD_Notifications\AD_Change_Notifications\AD_Change_Notifications\AD_Change_Notifications.obj AD_Change_Notifications
From what I have been reading its a linker error, which is kinda obvious, but it is all in 1 file, so I don't understand what I am suppose to be linking?
The best answer I found in java is quoted below from https://community.oracle.com/thread/1158217
/**
* ldapnotify.java
* December 2004
* Sample JNDI application that uses AD LDAP Notification Control.
*
**/
import java.util.Hashtable;
import java.util.Enumeration;
import javax.naming.*;
import javax.naming.ldap.*;
import com.sun.jndi.ldap.ctl.*;
import javax.naming.directory.*;
class NotifyControl implements Control {
public byte[] getEncodedValue() {
return new byte[] {};
}
public String getID() {
return "1.2.840.113556.1.4.528";
}
public boolean isCritical() {
return true;
}
}
class ldapnotify {
public static void main(String[] args) {
Hashtable env = new Hashtable();
String adminName = "CN=Administrator,CN=Users,DC=antipodes,DC=com";
String adminPassword = "XXXXXXXX";
String ldapURL = "ldap://mydc.antipodes.com:389";
String searchBase = "DC=antipodes,DC=com";
//For persistent search can only use objectClass=*
String searchFilter = "(objectClass=*)";
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
//set security credentials, note using simple cleartext authentication
env.put(Context.SECURITY_AUTHENTICATION,"simple");
env.put(Context.SECURITY_PRINCIPAL,adminName);
env.put(Context.SECURITY_CREDENTIALS,adminPassword);
//connect to my domain controller
env.put(Context.PROVIDER_URL,ldapURL);
try {
//bind to the domain controller
LdapContext ctx = new InitialLdapContext(env,null);
// Create the search controls
SearchControls searchCtls = new SearchControls();
//Specify the attributes to return
String returnedAtts[] = null;
searchCtls.setReturningAttributes(returnedAtts);
//Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
//Specifiy the search time limit, in this case unlimited
searchCtls.setTimeLimit(0);
//Request the LDAP Persistent Search control
Control[] rqstCtls = new Control[]{new NotifyControl()};
ctx.setRequestControls(rqstCtls);
//Now perform the search
NamingEnumeration answer = ctx.search(searchBase,searchFilter,searchCtls);
SearchResult sr;
Attributes attrs;
//Continue waiting for changes....forever
while(true) {
System.out.println("Waiting for changes..., press Ctrl C to exit");
sr = (SearchResult)answer.next();
System.out.println(">>>" + sr.getName());
//Print out the modified attributes
//instanceType and objectGUID are always returned
attrs = sr.getAttributes();
if (attrs != null) {
try {
for (NamingEnumeration ae = attrs.getAll();ae.hasMore();) {
Attribute attr = (Attribute)ae.next();
System.out.println("Attribute: " + attr.getID());
for (NamingEnumeration e = attr.getAll();e.hasMore();System.out.println(" " + e.next().toString()));
}
}
catch (NullPointerException e) {
System.err.println("Problem listing attributes: " + e);
}
}
}
}
catch (NamingException e) {
System.err.println("LDAP Notifications failure. " + e);
}
}
}

Rename feature for EMF Resources

I'm working with a project, where I have EMF model 'A' which is referenced in many other models 'B','C'... etc. What I want is I want to give a rename feature for these resources. So when user renames 'A', its references have to be updated.
Please provide some idea on it, if there is any frame work for this or I have to get all the references and then programmatically iterate and update the references.
I solved the same problem in another way.
The fundamental problem is that a referenced resource file might be renamed, and this breaks the references.
Instead of a refactoring that automatically updates all references I created a Repair File References command, which the user can invoke on an edited model.
The command performs these steps:
Prompts the user to select a missing resource to repair
Prompts the user to select a replacement file
Updates all objects in the model that has a proxy URI that matches the missing resource. Replaces proxies with resolved objects in the new resource.
If you still want to make a refactoring instead, I think you anyway can use my code as a starting point.
/**
* Locates and fixes unresolved references in a model.
*/
public class ReferenceRepairer {
public static final String COMMAND_ID = Activator.PLUGIN_ID + ".commands.repairReferences";
/**
* 1) Prompts the user to select a missing resource to repair
* 2) Prompts the user to select a replacement file
* 3) Updates all objects in the model with a proxy URI that matches the missing resource. Replaces proxies
* with resolved objects in the new resource.
*/
public static void repairResourceReference(Shell shell, EditingDomain editingDomain) {
Resource res = promptMissingResource(shell, editingDomain);
if (res == null) return;
IFile newFile = promptReplacementFile(shell);
if (newFile == null) return;
repairReferences(editingDomain, res, URI.createPlatformResourceURI(newFile.getFullPath().toString(), true));
}
private static void repairReferences(final EditingDomain editingDomain, Resource missingRes, final URI newUri) {
URI missingUri = missingRes.getURI();
// Create new resource for the replacement file
Resource newRes = editingDomain.getResourceSet().getResource(newUri, true);
Map<EObject, Collection<Setting>> proxies = UnresolvedProxyCrossReferencer.find(editingDomain.getResourceSet());
CompoundCommand repairRefsCommand = new CompoundCommand("Repair references") {
/**
* Disallow undo. The model changes could be undone, but it seems impossible to
* recreate a non-existent resource in the resource set.
*/
#Override
public boolean canUndo() {
return false;
}
};
// Resolve all proxies from this resource and repair reference to those objects
for (Entry<EObject, Collection<Setting>> entry : proxies.entrySet()) {
EObject proxy = entry.getKey();
URI proxyUri = EcoreUtil.getURI(proxy);
if (!proxyUri.trimFragment().equals(missingUri)) continue;
EObject resolved = newRes.getEObject(proxyUri.fragment());
if (resolved.eIsProxy()) continue;
// Update all objects that have references to the resolved proxy
for (Setting sett : entry.getValue()) {
if (sett.getEStructuralFeature().isMany()) {
#SuppressWarnings("unchecked")
EList<Object> valueList = (EList<Object>) sett.get(true);
int proxyIx = valueList.indexOf(proxy);
repairRefsCommand.append(SetCommand.create(editingDomain,
sett.getEObject(), sett.getEStructuralFeature(), resolved, proxyIx));
} else {
repairRefsCommand.append(SetCommand.create(editingDomain,
sett.getEObject(), sett.getEStructuralFeature(), resolved));
}
}
}
if (!repairRefsCommand.isEmpty()) {
editingDomain.getCommandStack().execute(repairRefsCommand);
}
// Remove the
editingDomain.getResourceSet().getResources().remove(missingRes);
}
private static IFile promptReplacementFile(Shell shell) {
ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(shell,
new WorkbenchLabelProvider(), new WorkbenchContentProvider());
dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
dialog.setTitle("Select Replacement Resource");
dialog.setMessage("Select a file which will replace the missing file.");
dialog.setValidator(new ISelectionStatusValidator() {
#Override
public IStatus validate(Object[] selection) {
if (selection.length == 0 || !(selection[0] instanceof IFile)) {
return ValidationStatus.error("The selected object is not a file.");
}
return new Status(IStatus.OK, Activator.PLUGIN_ID, "");
}
});
if (dialog.open() != Window.OK) return null;
return (IFile) dialog.getFirstResult();
}
private static Resource promptMissingResource(Shell shell, EditingDomain editingDomain) {
ElementListSelectionDialog dialog = new ElementListSelectionDialog(shell,
new LabelProvider() {
#Override
public String getText(Object elem) {
return ((Resource) elem).getURI().toString();
}
})
{
/** Make dialog OK button enabled when there are errors, instead of vise-versa. */
#Override
protected void updateButtonsEnableState(IStatus status) {
Button okButton = getOkButton();
if (okButton != null && !okButton.isDisposed()) {
okButton.setEnabled(!status.isOK());
}
}
/** Disable filter text field */
#Override
protected Text createFilterText(Composite parent) {
Text text = super.createFilterText(parent);
text.setSize(0, 0);
text.setLayoutData(GridDataFactory.swtDefaults().exclude(true).create());
text.setVisible(false);
return text;
}
};
dialog.setTitle("Select Missing Resource");
dialog.setMessage(
"Select a URI of a missing resource file that should be replaced by an URI to an existing file.");
dialog.setElements(getMissingResources(editingDomain.getResourceSet().getResources()).toArray());
if (dialog.open() != Window.OK) return null;
return (Resource) dialog.getFirstResult();
}
private static List<Resource> getMissingResources(List<Resource> resources) {
List<Resource> missingResources = new ArrayList<>();
for (Resource res : resources) {
try {
if (res.getURI().isPlatformPlugin()) continue;
URL url = FileLocator.toFileURL(new URL(res.getURI().toString()));
java.net.URI uri = new java.net.URI(url.getProtocol(), "", "/" + url.getPath(), null);
if (!Files.exists(Paths.get(uri))) {
missingResources.add(res);
}
} catch (InvalidPathException | IOException | URISyntaxException exc) {
// Ignore. There mighe be weird Sirius resource in the resources set which we can't recognice
}
}
return missingResources;
}
}

How can I override the test method name that appears on the TestNG report?

How can I override the test name that appears on the TestNG report? I want to override the name that appears in the middle column (currently shows as the method name). Is this even possible?
I tried to do it like this, but it didn't work.
public class EchApiTest1 extends TestBase {
...
#BeforeTest
public void setUp() {
restClient = new RestClientPost();
this.setTestName( "ech: XXXXXX" );
}
And, the base class:
import org.testng.ITest;
public class TestBase implements ITest {
String testName = "";
#Override
public String getTestName() {
return this.testName;
}
public void setTestName( String name ) {
this.testName = name;
}
}
NOTE: The above code does work when I am viewing the report detail in the Jenkins TestNG plugin report, which shows the overridden test name as a string called "Instance Name:" at the beginning of the Reporter log output. Why, in this case, WHY does a "setTestName()" method alter a string labeled "Instance Name" in the report?
One answer I found had a suggestion like this but I don't know how to pass an ITestResult arg to a AfterMethod method:
#AfterMethod
public void setResultTestName( ITestResult result ) {
try {
BaseTestMethod bm = (BaseTestMethod)result.getMethod();
Field f = bm.getClass().getSuperclass().getDeclaredField("m_methodName");
f.setAccessible(true);
f.set( bm, bm.getMethodName() + "." + your_customized_name );
} catch ( Exception ex ) {
Reporter.log( "ex" + ex.getMessage() );
}
Thoughts?
Please find following code for set custom name of testcase in TestNG reports.
Following features are available in this code.
Dynamic execution on same test-case in multiple time
Set custom test-case name for reports
Set parallel execution of multiple test-cases execution
import java.lang.reflect.Field;
import org.testng.ITest;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
import org.testng.internal.BaseTestMethod;
import com.test.data.ServiceProcessData;
public class ServiceTest implements ITest {
protected ServiceProcessData serviceProcessData;
protected String testCaseName = "";
#Test
public void executeServiceTest() {
System.out.println(this.serviceProcessData.toString());
}
#Factory(dataProvider = "processDataList")
public RiskServiceTest(ServiceProcessData serviceProcessData) {
this.serviceProcessData = serviceProcessData;
}
#DataProvider(name = "processDataList", parallel = true)
public static Object[] getProcessDataList() {
Object[] serviceProcessDataList = new Object[0];
//Set data in serviceProcessDataList
return serviceProcessDataList;
}
#Override
public String getTestName() {
this.testCaseName = "User custom testcase name";
// this.testCaseName = this.serviceProcessData.getTestCaseCustomName();
return this.testCaseName;
}
#AfterMethod(alwaysRun = true)
public void setResultTestName(ITestResult result) {
try {
BaseTestMethod baseTestMethod = (BaseTestMethod) result.getMethod();
Field f = baseTestMethod.getClass().getSuperclass().getDeclaredField("m_methodName");
f.setAccessible(true);
f.set(baseTestMethod, this.testCaseName);
} catch (Exception e) {
ErrorMessageHelper.getInstance().setErrorMessage(e);
Reporter.log("Exception : " + e.getMessage());
}
}}
Thanks
I found a "workaround" but I am hoping for a better answer. I want to be able to show this "test name" OR "instance name" value on the HTML report (not just within the Reporter.log output) and I am starting to think its not possible :
#Test(dataProvider = "restdata2")
public void testGetNameFromResponse( TestArguments testArgs ) {
this.setTestName( "ech: " + testArgs.getTestName() );
Reporter.log( getTestName() ); // this magic shows test name on report
....
With this workaround, the user can now identify which test it was by looking at the Reporter.log output but I still wish the name was more prominant.
I suspect the answer lies in writing a TestListenerAdapter that somehow overrides the ITestResult.getTestNameMethod() method? That is the holy grail I am looking for.
The ‘result’ object will automatically pass in the method setResultTestName( ITestResult result )
Make sure you put alwaysRun=true like the following when you have groups defined in your test class otherwise “AfterMethod” will not be excuted.
#AfterMethod (alwaysRun=true)

How do I invoke Multiple Startup Projects when running a unit tests in Debug Mode

This seems like a simple thing to do but I can't seem to find any info anywhere! I've got a solution that has a service that we run in 'Console Mode' when debugging. I want it to be started and 'attached' when I run my unit test from Visual Studio.
I'm using Resharper as the unit test runner.
Not a direct answer to your question, BUT
We faced a similar problem recently and eventually settled on a solution using AppDomain
As your solution is already running as a Console project it would be little work to make it boot in a new AppDomain. Furthermore, you could run Assertions on this project as well as part of unit testing. (if required)
Consider the following static class Sandbox which you can use to boot multiple app domains.
The Execute method requires a Type which is-a SandboxAction. (class definition also included below)
You would first extend this class and provide any bootup actions for running your console project.
public class ConsoleRunnerProjectSandbox : SandboxAction
{
protected override void OnRun()
{
Bootstrapper.Start(); //this code will be run on the newly create app domain
}
}
Now to get your app domain running you simply call
Sandbox.Execute<ConsoleRunnerProjectSandbox>("AppDomainName", configFile)
Note you can pass this call a config file so you can bootup your project in the same fashion as if you were running it via the console
Any more questions please ask.
public static class Sandbox
{
private static readonly List<Tuple<AppDomain, SandboxAction>> _sandboxes = new List<Tuple<AppDomain, SandboxAction>>();
public static T Execute<T>(string friendlyName, string configFile, params object[] args)
where T : SandboxAction
{
Trace.WriteLine(string.Format("Sandboxing {0}: {1}", typeof (T).Name, configFile));
AppDomain sandbox = CreateDomain(friendlyName, configFile);
var objectHandle = sandbox.CreateInstance(typeof(T).Assembly.FullName, typeof(T).FullName, true, BindingFlags.Default, null, args, null, null, null);
T sandBoxAction = objectHandle.Unwrap() as T;
sandBoxAction.Run();
Tuple<AppDomain, SandboxAction> box = new Tuple<AppDomain, SandboxAction>(sandbox, sandBoxAction);
_sandboxes.Add(box);
return sandBoxAction;
}
private static AppDomain CreateDomain(string name, string customConfigFile)
{
FileInfo info = customConfigFile != null ? new FileInfo(customConfigFile) : null;
if (!string.IsNullOrEmpty(customConfigFile) && !info.Exists)
throw new ArgumentException("customConfigFile not found using " + customConfigFile + " at " + info.FullName);
var appsetup = new AppDomainSetup();
//appsetup.ApplicationBase = Path.GetDirectoryName(typeof(Sandbox).Assembly.Location);
appsetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
if (customConfigFile==null)
customConfigFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
appsetup.ConfigurationFile = customConfigFile;
var sandbox = AppDomain.CreateDomain(
name,
AppDomain.CurrentDomain.Evidence,
appsetup);
return sandbox;
}
public static void DestroyAppDomainForSandbox(SandboxAction action)
{
foreach(var tuple in _sandboxes)
{
if(tuple.Second == action)
{
AppDomain.Unload(tuple.First);
Console.WriteLine("Unloaded sandbox ");
_sandboxes.Remove(tuple);
return;
}
}
}
}
[Serializable]
public abstract class SandboxAction : MarshalByRefObject
{
public override object InitializeLifetimeService()
{
return null;
}
public void Run()
{
string name = AppDomain.CurrentDomain.FriendlyName;
Log.Info("Executing {0} in AppDomain:{1} thread:{2}", name, AppDomain.CurrentDomain.Id, Thread.CurrentThread.ManagedThreadId);
try
{
OnRun();
}
catch (Exception ex)
{
Log.Error(ex, "Exception in app domain {0}", name);
throw;
}
}
protected abstract void OnRun();
public virtual void Stop()
{
}
}