Sitecore Handlers - sitecore

I am trying to create an event handler for sitecore .
I have done following steps.
create a dll named "TestEventHandlers" and
add its reference in bin folder of my website.
Add following line in my web.config events --> event node: <handler type="TestEventHandlers.EventHandler , TestEventHandlers" method="OnItemSaved"/>
But i am getting following error:
Could not resolve type name:
TestEventHandlers.EventHandler, TestEventHandlers.EventHandler
(method: Sitecore.Configuration.Factory.CreateType(XmlNode configNode, String[] parameters, Boolean assert)).
I am confused about assembly name in type attribute of handler.

The assembly-qualified name of a type consists of the type name, including its namespace, followed by a comma, followed by the display name of the assembly. > MSDN
The assembly-qualified name for you class might look like this:
TestEventHandlers.EventHandler, TestEventHandlers
Assuming that your dll (assembly) is named TestEventHandlers and the class you wrote is called EventHandler within the TestEventHandlers namespace. In other words, you have this code in your TestEventHandlers dll and that dll is in the bin directory of your Sitecore web site.
namespace TestEventHandlers
{
public class EventHandler
{
public void OnItemSaved(object sender, EventArgs args)
{
}
}
}

Assuming
dll name as- TestEventHandlers.dll , &
class description as - namespace TestEventHandlers.Events{ public class EventHandler{...}} your handler entry shuld be <
handler type="TestEventHandlers.Events.EventHandler , TestEventHandlers" method="OnItemSaved"/>

Related

Mapping #Json property with JDBI

According to JDBI document https://jdbi.org/#_jackson_2, it seems that it's quite straight forward to have a json property of your object model, however I've tried the following and it ran into many issues.
DB: Postgres with a column type of Jsonb
class Event {
private String name;
#Json
private EventProperty jsonProperty;
...
}
Datasource has been configured with
#Bean
public Jdbi jdbi(TransactionAwareDataSourceProxy eventStoreTxAwareDataSourceProxy) {
Jdbi jdbi = Jdbi.create(eventStoreTxAwareDataSourceProxy);
jdbi.installPlugin(new PostgresPlugin());
jdbi.installPlugin(new Jackson2Plugin());
}
SQL for binding list of insertion
INSERT INTO event (name, json_property)
VALUES (
:name,
:jsonProperty)
When running the code to insert, the following error occurred:
org.jdbi.v3.core.statement.UnableToCreateStatementException: no argument factory for type com.EventProperty [statement:"INSERT INTO event (...]
If I created EventPropertyArgumentFactory and using Jackson ObjectMapper and writeValueAsString then I can save it to DB. However, when retrieving it back from DB by
try (Handle handle = jdbi.open()) {
EventDao dao = handle.attach(EventDao.class);
return dao.findByName(name);
}
throws the following errors
java.lang.ClassCastException: Cannot cast org.postgresql.util.PGobject to com.EventProperty
I thought all I needed to do is declare the field annotated with #Json, the DB column has to be json/jsonb type and install the plugins, but seems like this is not the case?
Anyone has tried this successfully, without having to define custom row mapper and argument factory implementation?
Thanks
The documentation says:
// use #Json qualifier:
...
// also works on bean or property-mapped objects:
class MyBean {
private final MyJson property;
#Json
public MyJson getProperty() { return ...; }
}
I've checked and it's unfortunate but #Json only works when placed on a property( i.e. getter or setter) and not on a field.
You can make your work easier if you use Lombok library.
Modify lombok.config file by adding this line:
lombok.copyableannotations += org.jdbi.v3.json.Json
Now in bean declaration you can do this:
#Data // will generate setters and getters among other things
class Event {
private String name;
#Json // will be copied onto getter and setter due to config change we made
private EventProperty jsonProperty;
...
}
Have fun!
Not sure if you've figured this out by now but I just ran into this same issue and finally figured it out.
Basically, you just have to add the annotation on the getter or setter of the class, not the top-level field.
class Event {
private String name;
private EventProperty jsonProperty;
...
#Json
public getEventProperty() {
return jsonProperty;
}
}

Plugin re-using Target parameter between calls

I've created and deployed a plugin for the Update event of a custom entity but it seems when multiple users update different entities within quick succession the plugin uses the first entity it receives for each call.
To investigate further I added NLog via NuGet and at the beginning of the Execute function I generate a Guid and log the entity Id and the Guid. When I look in the log I can see the same ID and Guid logged 3-4 times before both change.
What I think is happening is the code is being run for each user but using the first entities details, applying only to the first entity.
Why is this happening and how can I stop it? The problem is users are saying the plugin is erratic.
Here is my code:
public class OnUpdateClaimSection : IPlugin
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private string logId = Guid.NewGuid().ToString();
public void Execute(IServiceProvider serviceProvider)
{
try
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
logger.Debug("{0} {1}|{2}|{3}", logId, context.MessageName, context.PrimaryEntityName, Common.GetSystemUserFullName(service, context.UserId));
var entity = context.InputParameters["Target"] as Entity;
logger.Debug("{0} {1}", logId, entity.Id);
var claimSection = GetClaimSection(service, entity.ToEntity<ClaimSection>());
CalculateClaimTotals(service, claimSection);
}
}
catch (Exception ex)
{
logger.Error("{0} Exception : {1}", logId, ex.Message);
throw;
}
}
}
Plugin classes are instantiated once by the CRM platform and are then reused for requests. Therefore you must be very careful when using class field variables, because they are not guaranteed to be thread-safe.
In your example field logId is modified in the Execute method. Race conditions of multiple threads are causing the effects you describe.
I suggest to only use plugin class fields when you have made sure that their implementation is absolutely thread-safe.

Domino: Webservice: Class do not have a property of the name

I have the following Problem.
I tried to create a web service a standard cmis Webservice Interface on IBM, Domino with wsdl2java (with cxf). After creating all java classes I tried to get answers from the webservice with the eclipse Java Client. It works find. After this test I import the generated java classes into a Domino Database.
Now I have the problem to run the webservice, because the following error message:
class org.oasis_open.docs.ns.cmis.messaging._200908.GetTypeDefinition
do not have a property of the name {URL..}repositoryId
In the JAVA Class the following code:
public class GetTypeDefinition {
#XmlElement(required = true)
protected String repositoryId;
#XmlElement(required = true)
protected String typeId;
#XmlElementRef(name = "extension", namespace = "http://docs.oasis-open.org/ns/cmis/messaging/200908/", type = JAXBElement.class)
protected JAXBElement<CmisExtensionType> extension;
The Domino JAVA Env. does not understand the Tag #XmlElement(required = true) without the name, namespace and the type definition.
If I add in the same line the following code:
#XmlElement(required = true, name = "repositoryId", namespace = "http://docs.oasis-open.org/ns/cmis/messaging/200908/", type = String.class)
protected String repositoryId;
it works (error then in the next line:
GetTypeDefinition do not have a property of the name {URL}typeId
Now the question is: why? Can I generate the java classes with an other tool (not with cxf wsdl2java) or do I need other parameters to get the complete code?
In the generated JAVA Classes are round about 170 lines with the problematic code.
Have somebody an Idea to solve the problem on the Domino Server (x64 9.0)?

Load 2 different input models in Acceleo

I'd like to load 2 different input models (a .bpel and a .wsdl) in my main template of Acceleo.
I loaded the ecore metamodels for both bpel and wsdl and I'd like to be able to use something like this:
[comment encoding = UTF-8 /]
[module generate('http:///org/eclipse/bpel/model/bpel.ecore','http://www.eclipse.org/wsdl/2003/WSDL')/]
[import org::eclipse::acceleo::module::sample::files::processJavaFile /]
[template public generate(aProcess : Process, aDefinition : Definition)]
[comment #main /]
Process Name : [aProcess.name/]
Def Location : [aDefinition.location/]
[/template]
but when I run the acceleo template I get this error:
An internal error occurred during: "Launching Generate".
Could not find public template generate in module generate.
I think I have to modify the java launcher (generate.java) because right now it can't take 2 models as arguments. Do you know how?
Thanks!
** EDIT from Kellindil suggestions:
Just to know if I understood it right, before I get to modify stuff:
I'm trying to modify the Generate() constructor.
I changed it in:
//MODIFIED CODE
public Generate(URI modelURI, URI modelURI2, File targetFolder,
List<? extends Object> arguments) {
initialize(modelURI, targetFolder, arguments);
}
In the generic case, I can see it calls the AbstractAcceleoGenerator.initialize(URI, File, List>?>), shall I call it twice, once per each model? like:
initialize(modelURI, targetFolder, arguments);
initialize(modelURI2, targetFolder, arguments);
Then, to mimic in my Generate() constructor the code that is in the super-implementation:
//NON MODIFIED ACCELEO CODE
Map<String, String> AbstractAcceleoLauncher.generate(Monitor monitor) {
File target = getTargetFolder();
if (!target.exists() && !target.mkdirs()) {
throw new IOException("target directory " + target + " couldn't be created."); //$NON-NLS-1$ //$NON-NLS-2$
}
AcceleoService service = createAcceleoService();
String[] templateNames = getTemplateNames();
Map<String, String> result = new HashMap<String, String>();
for (int i = 0; i < templateNames.length; i++) {
result.putAll(service.doGenerate(getModule(), templateNames[i], getModel(), getArguments(),
target, monitor));
}
postGenerate(getModule().eResource().getResourceSet());
originalResources.clear();
return result;
}
what shall I do? Shall I try to mimic what this method is doing in my Generate() constructor after the initialize() calls?
What you wish to do is indeed possible with Acceleo, but it is not the "default" case that the generated launcher expects.
You'll have to mark the "generate" method of the generated java class as "#generated NOT" (or remove the "#generated" annotation from its javadoc altogether). In this method, what you need to do is mimic the behavior of the super-implementation (in AbstractAcceleoLauncher) does, loading two models instead of one and passing them on to AcceleoService#doGenerate.
In other words, you will need to look at the API Acceleo provides to generate code, and use it in the way that fits your need. Our generated java launcher and the AcceleoService class are there to provide an example that fits the general use case. Changing the behavior can be done by following these samples.
You should'nt need to modify the Generate.java class. By default, it should allow you to perform the code generation.
You need to create a launch config and provide the right arguments (process and definition) in this launch config, that's all.
I don't understand the 'client.xmi' URI that is the 1st argument of your module. It looks like it is your model file, if so remove it from the arguments, which must only contain your metamodels URIs.

Web Service: Specifying XML Serialization element names for generic types

I've created a web service that uses a generic type Response<TCode, TData> and so I'm ending up with elements like
ResponseOfResponseCodeUserData
ResponseOfResponseCodeArrayOfRightData
etc.
Functionally works just fine but I'm wondering if there's a way to name these particular elements?
EDIT:
Here's an example.
[return: XmlElement("AuthenticationResponse")]
[WebMethod]
public Response<ResponseCode, AuthenticationData> AuthenticateProcess(string ProcessName, string Password)
{
// ... Code ...
}
Still returns
<ResponseOfResponseCodeAuthenticationData (...) >
Any ideas?
It might help if you were to show some code.
Still, look at the [XmlElementAttribute] attribute, which allows you to specify the element name. If your issue is with return values, then you will need to use
[return: XmlRoot("ReturnElementName")]
[WebMethod]
public int MyWebMethod() { ... }