An alternative to UBB.threads
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
FLocal/Patcher/Data/Patch/AbstractPatch.cs

153 lines
4.4 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using Web.Core;
using Patcher.Data.Command;
using Patcher.DB;
namespace Patcher.Data.Patch
{
abstract class AbstractPatch
{
private static class Checker
{
private static XmlSchemaSet LoadXsd()
{
XmlSchemaSet schemaSet = new XmlSchemaSet();
using(Stream xsdStream = Resources.ResourcesManager.GetResource("IPatch.xsd"))
{
using(XmlReader xsdReader = XmlReader.Create(xsdStream))
{
schemaSet.Add("", xsdReader);
}
}
schemaSet.Compile();
return schemaSet;
}
private static readonly XmlSchemaSet Xsd = LoadXsd();
public static void Check(XDocument document)
{
document.Validate(Xsd, (sender, e) => { throw new ApplicationException("Intermediate XML validation failed: " + e.Message, e.Exception); });
}
}
public static AbstractPatch LoadById(PatchId id, Context context)
{
return Cache<AbstractPatch>.instance.get(new KeyValuePair<PatchId, Context>(id, context), () => _LoadById(id, context));
}
private static AbstractPatch _LoadById(PatchId id, Context context)
{
XDocument data;
using(Stream xmlStream = context.loadPatch(id))
{
using(XmlReader reader = XmlReader.Create(xmlStream))
{
data = XDocument.Load(reader);
}
}
Checker.Check(data);
XElement version = data.Root.Element("version");
string number = version.Element("number").Value;
string author = version.Element("author").Value;
if((number != id.version.ToString()) || (author != id.name))
{
throw new ApplicationException(string.Format("Versions mismatch on patch #{0} from {1} (got #{2} from {3})", id.version, id.name, number, author));
}
HashSet<string> restrictToEnvironments;
if(data.Root.Element("restrictToEnvironments") != null)
{
restrictToEnvironments = new HashSet<string>(from elem in data.Root.Element("restrictToEnvironments").Elements() select elem.Value);
} else
{
restrictToEnvironments = new HashSet<string>();
}
XElement commandSet;
bool isStrictCommandSet;
{
XElement strictCommandSet = data.Root.Element("strictCommandSet");
XElement looseCommandSet = data.Root.Element("looseCommandSet");
if (strictCommandSet != null && looseCommandSet == null)
{
commandSet = strictCommandSet;
isStrictCommandSet = true;
} else if (strictCommandSet == null && looseCommandSet != null)
{
commandSet = looseCommandSet;
isStrictCommandSet = false;
} else if (strictCommandSet != null && looseCommandSet != null)
{
throw new ApplicationException("Malformed XML: both strictCommandSet and looseCommandSet found");
} else
{
throw new ApplicationException("Malformed XML: no CommandSet found");
}
}
var commands = (from elem in commandSet.Elements() select AbstractCommand.Create(elem)).ToArray();
if(isStrictCommandSet)
{
var isPersistent = commands.OfType<AbstractPersistentCommand>().Any();
if (isPersistent)
{
if (commands.Length != 1)
{
throw new ApplicationException("More than one persistent command");
}
if(context.DbDriver.IsDDLTransactional)
{
return new AtomicPatch(commands, true, restrictToEnvironments, context);
} else
{
return new PersistentPatch(commands[0], restrictToEnvironments, context);
}
}
else
{
return new AtomicPatch(commands, true, restrictToEnvironments, context);
}
} else
{
return new AtomicPatch(commands, false, restrictToEnvironments, context);
}
}
private readonly HashSet<string> restrictToEnvironments;
protected readonly Context context;
protected AbstractPatch(HashSet<string> restrictToEnvironments, Context context)
{
this.restrictToEnvironments = restrictToEnvironments;
this.context = context;
}
public abstract XDocument Apply(Transaction transaction);
public abstract void Rollback(Transaction transaction, XDocument rollbackInfo);
public bool DoesSupportEnvironment(string environmentName)
{
if(restrictToEnvironments.Any())
{
return restrictToEnvironments.Contains(environmentName);
} else
{
return true;
}
}
}
}