Alfresco CMIS: How to translate a ChangeEvent object id to a Document object id? - alfresco

Context
In CMIS, a ChangeEvent tells me that an object has been deleted on the remote server, and that the objectId of this object is for instance workspace://SpacesStore/3aca9034-3f53-4946-a0d9-ebcf054912a2;1.0 (real example of ChangeEvent.Properties[cmis:objectId]).
I locally kept the various identifiers of all objects, but none of the identifiers match exactly the identifier in the ChangeEvent:
Document.Properties[cmis:objectId] is
3aca9034-3f53-4946-a0d9-ebcf054912a2;1.0
Document.Properties[alfcmis:nodeRef] is
workspace://SpacesStore/3aca9034-3f53-4946-a0d9-ebcf054912a2.
Question
How should I translate from ChangeEvent.Properties[cmis:objectId] to Document.Properties[cmis:objectId]?
(eg. from workspace://SpacesStore/3aca9034-3f53-4946-a0d9-ebcf054912a2;1.0 to 3aca9034-3f53-4946-a0d9-ebcf054912a2;1.0
I could just remove the first 24 characters, but I guess it would only work for Alfresco, and not with other CMIS servers.
Environment
Alfresco Community 4.2.e accessed by DotCMIS via
http://server/alfresco/api/-default-/public/cmis/versions/1.0/atom

Need to assign from DotCMIS from Alfresco apache chemeistry support please go through below code for access object id from file name using c#..
IFolder selectedFolder1 = session1.GetObject(ObjectID) as IFolder;
foreach (ICmisObject cmisObject in selectedFolder1.GetChildren())
{
if (cmisObject.GetType() != typeof(DotCMIS.Client.Impl.Folder))
{
if (cmisObject.Name.Contains(Uid))
{
return false;
}
}
}

Related

Manually create spring cloud stream bindings based on dynamic configuration

I have a requirement where one or more spring cloud stream kafka-streams bindings need to be created based on dynamic configuration. By dynamic config I mean stream bindings (input-output) will be specified run-time. Either via external property file or from database.
E.g We need to create multiple stream processors where input output topic pairs and relevant configs are provided. Then code should loop through this config create and start those bindings.
In spring cloud stream we write this in a java file
#StreamListener(StreamBindings.INPUT)
#SendTo(StreamBindings.OUTPUT)
public KStream<String,String> process(KStream<String,String> inputStream) {
return inputStream
.map( ... )
.selectKey( ... )
.mapValues( ... );
}
Where StreamBindings is like
public interface StreamBindings {
String INPUT = "input-topic";
String OUTPUT = "output-topic";
#Input(INPUT)
KStream<String,String> inputStream();
#Input(OUTPUT)
KStream<String,String> outputStream();
}
Now I want a piece of code to create this in run-time based on info I specified above.
Can this be done and how? And can we specify body of process function as an argument, like some kind of message handler?

Getting NServiceBus Subscriptions from RavenDB

Has anyone tried (and succeeded) to get subscriptions out of RavenDB with the Raven DB .Net client?
Having some Json serialisation issues that when the following runs, it throws with a
"Error converting value "Subscriber.Messages.Events.MyEvent, Version=1.0.0.0" to type 'NServiceBus.Unicast.Subscriptions.MessageType'. message
The code is simple :
var documentStore = new DocumentStore
{
Url = "http://localhost:8080/",
DefaultDatabase = "publisher",
};
documentStore.Initialize();
using (var session = documentStore.OpenSession())
{
return session.Query<NServiceBus.Unicast.Subscriptions.Raven.Subscription>("Raven/DocumentsByEntityName").ToArray();
}
It's definitely a serialisation issue as the retrieval works. As it does using the alternative below:
session.Advanced.LuceneQuery<Subscription>("Raven/DocumentsByEntityName").QueryResult.Results[0]
In the RaveDB studio I can see the following document in the publisher database.
{
"MessageType": "Subscriber.Messages.Events.MyEvent, Version=1.0.0.0",
"Clients": [
{
"Queue": "samplesubscriber",
"Machine": "myDesktopHere"
}
]
}
Error converting value "Subscriber.Messages.Events.MyEvent, Version=1.0.0.0" to type 'NServiceBus.Unicast.Subscriptions.MessageType'.
Anyone have a clue why the serialization fails?
I'm using NServiveBus.Host 4.2, Raven-DB client 1.0.616, and Newtonsoft.json 4.0.5.
Incidentally I've pulled up the types using dotpeek and created local versions. I created my own subcription, MessageType, MessageTypeConvertor from the NSB dll's. I then managed to deserialise the strings without issue. Any thoughts?
EDIT
As per suggestions the advance Lucene query does a great job of retrieving the results. But then deserialization fails. For example, search results are returned in the first line, but fail to deserlize in the return statement. I've pulled up a local version of the Subscription type from the NSB dll's, and implemented the type converter, again pulled up from the NSB libraries, and using those in place of NServiceBus.Unicast.Subscriptions.Raven.Subscription works fine. Inevitably, that's not a stable choice.
var searchResults = session.Advanced.LuceneQuery<NServiceBus.Unicast.Subscriptions.Raven.Subscription>("Raven/DocumentsByEntityName").WhereEquals("Tag", "Subscription").QueryResult.Results;
return searchResults.Select(subscriptionJsonObject => JsonConvert.DeserializeObject<NServiceBus.Unicast.Subscriptions.Raven.Subscription>(subscriptionJsonObject.ToString())).ToList();
Any further thoughts?
When you query with this form:
session.Query<Entity>("IndexName")
You are asking for all items of that index to be returned from the query, and then telling the RavenDB client to deserialize them all as the type you specified.
Normally, that works out quite well because a specific index would be built for the types you're working with. For example, you would usually build your own index of subscriptions for a specific purpose, and query that:
session.Query<Subscription>("Subscriptions/ByWhatever")
or if you built the index from C#, you might like this syntax instead to avoid the string:
session.Query<Subscription, Subscriptions_ByWhatever>()
You could also just let Raven build an index for you automatically:
session.Query<Subscription>()
Since you used the built-in Raven/DocumentsByEntityName index, you are returning all documents in the database, not just those that are subscriptions. Since only some can be deserialized as a Subscription type, the others are failing with serialization errors.
If you'd like to continue to use that index, you would need to filter it to just those of that type:
session.Advanced.LuceneQuery<Subscription>("Raven/DocumentsByEntityName")
.WhereEquals("Tag", "Subscriptions")
The LuceneQuery form is easier here, since you are filtering a field by its string name.
You could use a regular LINQ query, but you'd have to create a type that contains the Tag field, like this:
class RDBENIndexEntry
{
public string Tag { get; set; }
}
...
session.Query<RDBENIndexEntry>("Raven/DocumentsByEntityName")
.Where(x => x.Tag == "Subscriptions").OfType<Subscription>()

Referencing a port in an orchestration via a string variable

I am attempting to develop a generic BizTalk application for configuring dynamic ports. I have an orchestration that pulls back all the configuration settings for each port and I want to loop through these settings and configure the ports. The settings are held in MSSQL and, for instance, two of the properties are PortName and Address. So from within the orchestration I would like to reference the port by the string variable PortName. So is there some way to get a collection of all the ports in an orchestration or reference a port via a string variable i.e. Port['MyPortName'](Microsoft.XLANGs.BaseTypes.Address) = "file://c:\test\out\%MessageId%.xml" Thanks
In order to dynamically configure Dynamic Logical Send Ports from within an orchestration, one has to store the settings into a persistent datastore (e.g. a database or configuration file) and implement a way to assign those properties dynamically at runtime.
But first, we need to understand what is happening when configurating a Dynamic Send Port.
How to Configure a Dynamic Logical Send Port
Configuring the properties of a dynamic logical send port from within an orchestration involves two steps:
First, the TransportType and target Address properties must be specified on the Send Port. This is usually done in an Expression Shape with code similar to this:
DynamicSendPort(Microsoft.XLANGs.BaseTypes.TransportType) = "FILE";
DynamicSendPort(Microsoft.XLANGs.BaseTypes.Address) = "C:\Temp\Folder\%SourceFileName%";
Second, any additional transport properties must be specified on the context of the outgoing message itself. Virtually all BizTalk adapters have additional properties that are used for the communication between the Messaging Engine and the XLANG/s Orchestration Engine. For instance, the ReceivedFileName context property is used to dynamically set a specific name for when the FILE adapter will save the outgoing message at its target location. This is best performed inside an Assignment Shape, as part of constructing the outgoing message:
OutgoingMessage(FILE.ReceiveFileName) = "HardCodedFileName.xml"
You'll notice that most configuration properties must be specified on the context of the outgoing messages, specifying a namespace prefix (e.g. FILE), a property name (e.g. ReceiveFileName) and, obviously, the value that gets assigned to the corresponding property.
In fact, all the context properties are classes that live Inside the well-known Microsoft.BizTalk.GlobalPropertySchemas.dll assembly. This is confirmed by looking up this assembly in Visual Studio's object explorer.
Even though most context properties that are necessary to configure Dynamic Logical Send Ports live Inside this specific assembly, not all of them do. For instance, the MSMQ BizTalk adapter uses a separate assembly to store its context properties. Obviously, third-party or custom adapters come with additionnal assemblies as well.
Therefore, in order to setup a context property on a Dynamic Send Port using a flexible approach like the one describe below, four pieces of information are necessary:
The fully qualified name of the assembly containing the context property classes.
The namespace prefix.
The property name.
The property value.
Storing Port Settings in a Persistent Medium
The following .XSD schema illustrate one possible structure for serializing port settings.
Once serialized, the specified context properties can then be stored in a SQL database or a configuration file very easily. For instance, here are the settings used as an example in this post:
A Flexible Approach to Configuring Dynamic Logical Send Ports
With a simple helper Library, setting up the dynamic port configuration is very easy. First, you have to retrieve the serialized settings from the persistent medium. This can easily be achieved using the WCF-SQL Adapter and a simple stored procedure.
Once retrieved, those properties can then be deserialized into a strongly-typed C# object graph. For this, first create a C# representation of the ContextProperties schema shown above, using the following command-line utility:
xsd.exe /classes /language:cs /namespace:Helper.Schemas .\ContextProperties.xsd
This generates a partial class that can be improved with the following method:
namespace Helper.Schemas
{
public partial class ContextProperties
{
public static ContextProperties Deserialize(string text)
{
using (MemoryStream stream = new MemoryStream())
{
byte[] buffer = Encoding.UTF8.GetBytes(text);
stream.Write(buffer, 0, buffer.Length);
stream.Seek(0, SeekOrigin.Begin);
return (ContextProperties)
Deserialize(
stream
, typeof(ContextProperties));
}
}
public static Object Deserialize(Stream stream, Type type)
{
XmlSerializer xmlSerializer = new XmlSerializer(type);
return xmlSerializer.Deserialize(stream);
}
}
}
Second, applying this configuration involves creating an XLANG/s message from code and setting up the context properties dynamically using reflection, based upon the description of the context property classes specified in the deserialized ContextProperties object graph.
For this, I use a technique borrowed from Paolo Salvatori's series of articles regarding dynamic transformations, which consists in creating a custom BTXMessage-derived class, used internally by the BizTalk XLANG/s engine.
namespace Helper.Schemas
{
using Microsoft.BizTalk.XLANGs.BTXEngine; // Found in Microsoft.XLANGs.BizTalk.Engine
using Microsoft.XLANGs.Core; // Found in Microsoft.XLANGs.Engine
[Serializable]
public sealed class CustomBTXMessage : BTXMessage
{
public CustomBTXMessage(string messageName, Context context)
: base(messageName, context)
{
context.RefMessage(this);
}
public void SetContextProperty(string assembly, string ns, string name, object value)
{
if (String.IsNullOrEmpty(ns))
ns = "Microsoft.XLANGs.BaseTypes";
if (String.IsNullOrEmpty(assembly))
assembly = "Microsoft.BizTalk.GlobalPropertySchemas";
StringBuilder assemblyQualifiedName = new StringBuilder();
assemblyQualifiedName.AppendFormat("{0}.{1}, {2}", ns, name, assembly);
Type type = Type.GetType(assemblyQualifiedName.ToString(), true, true);
SetContextProperty(type, value);
}
internal void SetContextProperty(string property, object value)
{
int index = property.IndexOf('.');
if (index != -1)
SetContextProperty(String.Empty, property.Substring(0, index), property.Substring(index + 1), value);
else
SetContextProperty(String.Empty, String.Empty, property, value);
}
}
}
Now, the last piece of the puzzle is how to make use of this custom class from within an Orchestration. This is easily done in an Assignment Shape using the following helper code:
namespace Helper.Schemas
{
using Microsoft.XLANGs.BaseTypes;
using Microsoft.XLANGs.Core; // Found in Microsoft.XLANGs.Engine
public static class Message
{
public static XLANGMessage SetContext(XLANGMessage message, ContextProperties properties)
{
try
{
// create a new XLANGMessage
CustomBTXMessage customBTXMessage = new CustomBTXMessage(message.Name, Service.RootService.XlangStore.OwningContext);
// add parts of the original message to it
for (int index = 0; index < message.Count; index++)
customBTXMessage.AddPart(message[index]);
// set the specified context properties
foreach (ContextPropertiesContextProperty property in properties.ContextProperty)
customBTXMessage.SetContextProperty(property.assembly, property.#namespace, property.name, property.Value);
return customBTXMessage.GetMessageWrapperForUserCode();
}
finally
{
message.Dispose();
}
}
}
}
You can use this static method inside your Assignment Shape like the code shown hereafter, where OutboundMessage represents the message which you want to set the context:
OutboundMessage = Helper.Schemas.Message.SetContext(OutboundMessage, contextProperties);
In the first place you shouldn't attempt to do configuration changes like this using an Orchestration. Technically it's feasible to do what you are attempting to do, but as a practice you shouldn't mix up your business process with administration.
The best way to do such things will be by either writing some normal scripts or PowerShell.
To answer you question, you can get the data you want from BtsOrchestration class in ExplorerOM
http://msdn.microsoft.com/en-us/library/microsoft.biztalk.explorerom.btsorchestration_members(v=bts.20)

Changing website according to subdomain

I have a website written in ASP.NET.
I would like to add subdomains of states. such as nevada.mysite.com.
However, I'd like my whole site to be custom made for that subdomain.
That is, I'd like to capture in each page which subdomain context I am and show different things.
I do not want to seperate to different websites. I want them all to reside in the same website in the IIS
what is the best and proper way of handling such issue?
where do you suggest to hold and save the global variable of the state?
Thanks!
First, have all of your subdomains point to a single IP address in DNS.
Next, configure IIS to listen for all connections on that IP (don't specify a host name)
Then write an HttpModule (or perhaps use Global.asax) with a handler for the BeginRequest event. Extract the subdomain name from the incoming URL, and store it in HttpContext.Items["state"] (the Items Dictionary is unique per request).
This is a great question. I've done this before except I didn't use sub domains, I used different URL's, but they still used the same code and database. I wanted a way to integrate this a bit more tightly with my LINQ to SQL code without having to type in where clauses on each one. Here's what I did:
public static IEnumerable<T> GetDataByDomain<T>(
IQueryable<T> src) where T:IDbColumn
{
//1 == website1
//2 == website2
//3 == both
string url = HttpContext.Current.Request.Url.Host;
int i = url == "localhost"
|| url == "website1.com"
|| url == "www.website1.com" ? 1 : 2;
return src.Where(x => x.domainID == i|| x.domainID == 3);
}
Basically when querying a table with LINQ to SQL I have my own custom where clause.
Used like so:
using (var db = new MyDataContext())
{
var items = Utility.GetDataByDomain(db.GetTable<Item>()).Where(x => x.isVisible);
}
Finally in each table where I had data that needed to be specified for one web site or both I added a column that took a value of 1,2 or 3(both). Additionally in my LINQ data context I made a partial class and referenced my interface:
public partial class Item : Utility.IDbColumn
{
}
The reason we need the following interface is because the first method takes an unknown type so obviously I can't select a property from an unknown type unless I tell it that any type I pass to it relies on an interface which contains that property.
Interface:
public interface IDbColumn
{
int domainID { get; set; }
}
It's kind of an interesting system, probably could have done it in many different ways. Built it a while ago and it works great.

ASP.NET Caching at data access layer (best practice question)

I currently have a LINQ 2 SQL data model and a supporting 'Passenger' repository class. The repository is as follows (off the top of my head so the code may have errors):
public class PassengerRepository
{
public static Passenger GetPassenger(int passengerId)
{
Passenger p = null;
// Linq to sql code to retrieve passenger by passengerId and store in 'p'
return p;
}
public static Passenger GetPassengerByUrl(string passengerUrl)
{
Passenger p = null
// Linq to sql code to retrieve passenger by passengerUrl and store in 'p'
return p;
}
}
On top of this, I have a PassengerController class as follows:
public class PassengerController
{
public static Passenger GetPassenger(int passengerId)
{
if (Cache["Passenger_" + passengerId] != null)
return (Passenger)Cache["Passenger_" + passengerId];
Passenger p = null;
p = PassengerRepository.GetPassenger(passengerId);
Cache["Passenger_" + passengerId] = p;
return p;
}
public static Passenger GetPassenger(string passengerUrl)
{
if (Cache["PassengerUrl_" + passengerUrl] != null)
return (Passenger)Cache["PassengerUrl_" + passengerUrl];
Passenger p = null;
p = PassengerRepository.GetPassengerByUrl(passengerUrl);
Cache["PassengerUrl_" + passengerUrl] = p;
return p;
}
}
PassengerId and PassengerUrl are always unique for a particular passenger.
My problem is that I am storing duplicates of the Passenger object if fetching by either Id or Url because the Cache keys will be different. When I fetch the data by Id, I am storing it in the cache with a key dependent on PassengerId and thus I can't check if that Passenger object has already been stored for a particular Url. This applies the other way, if fetching by Url, I can't check in the cache if a Passenger object exists for a particular Id. My questions are:
What would be the best way of only storing one instance of the Passenger object in the cache if fetching by either Url or Id? I was thinking maybe creating a Caching wrapper and then when fetching by Url, perhaps once I've got the Passenger datam I store the Passenger in the cache by Id, and then create a new key in the cache for Url and store a string variable with the keyname for the Passenger Id object. (i.e in the passenger Url key, I would store a reference to the passenger Id key).
On a side note, I have all my data access methods in the Controller/Repository classes as static - is this performant and efficient memory wise?
Am I putting my caching in the right place? Do most people put it in the repository class or is the controller an acceptable place to put it?
Any advice would be gratefully appreciated!
Cheers,
A.
If you give some more information about your system we may be more helpful. For example how many passengers will you have ? How powerful is your server etc, etc.
But with the given info I can say:
You can cache the Passenger objects in an array after finding them.
Then when you want make another search first search in this array. If the passenger is not found in your array, then go to database, get the passenger info, add the pasenger info to your array and return the found passenger info.
This way seems nice in my opinion. We use this also in some mid size web sites. If someone shows better options I'd appreciate also.
Coming back to this question after some time. I've come to the thought that this can be quite a subjective issue. For what it's worth, I actually ended up storing the Passenger by a key generated from the Passenger ID in the application cache, for example Passenger_100. Then I created a proxy object in the key that would generated from Passenger URL (Passenger_myurl), which acts as a reference back to the Passenger_100 key.

Resources