Synchronization of multiple catalogs in hybris - upgrade

I need help on this issue. I am upgrading hybris to version 2105, I ran into the problem that the 'DefaultSetupSyncJobService' class has changed its methods from 'SyncItemJob' to 'SyncItemJobModel'. How could I adapt these classes so that the catalogs are correctly synchronized ?

The new implementation for synchronization is stored in CatalogSynchronizationService.synchronizeFully(source,target) for a full synchronization. There are other methods to perform partial syncs with a select subset of items aswell in that service.
Do note that this will always create new SyncItemCronJobModel objects instead of reusing an existing syncjob. Depending on what you want, you can modify the implementation somewhat to reuse the same syncjob. The code then becomes something like this:
catalogSynchronizationService.getSyncJob(source, target, null);
instead of calling createSyncItemJob(...)
The rest is the same as the original implementation. So customized implementation of synchronizeFully could look something like(Extend from DefaultCatalogSynchronizationService)
public void synchronizeFully(final CatalogVersionModel source, final CatalogVersionModel target) {
final SyncItemJobModel syncJob = getSyncJob(source, target, null);
final SyncItemCronJobModel syncCronJob = createSyncCronJob(syncJob);
cronJobService.performCronJob(syncCronJob, true);
}

Related

Changing jasper report parameters in runtime

I know, but we really need it.
We have a clear division of labor.
They create templates, I fill them in runtime according to some rules.
Can't teach my business to insert something like this and be sure they really did it ok(so can't move any logic to templates):
$P{risk_types}.get($F{risk_type}) ?: "UNDEFINED"
Also can not fill from files hardcoded in some adapter hadwritten by god-knows-who and unchangeable in runtime. It's a web app. Best option is to find a way to replace that file source from adapter to a ByteArrayStream.
SO:
Need to substitute contents of parameters(also default ones) at runtime.
example:
need to set JSON_INPUT_STREAM
Like this unsolved thread.
https://community.jaspersoft.com/questions/516611/changing-parameter-scriptlet
Really hope not to work on xml level, but xml also can't solve my problem as far as I tried.
Thank you!
The easiest and cleanest way we did this(bypassing usage of tons of deprecated documentation and unfinished bugged undocumented static antipatterned new features):
Create context with repository extension
SimpleJasperReportsContext jasperReportsContext = new SimpleJasperReportsContext();
jasperReportsContext.setExtensions(RepositoryService.class, Collections.singletonList(new MyRepositoryService(jasperReportsContext, yourOptionalParams)));
Fill this way(after compile and other usual actions)
JasperPrint print = JasperFillManager.getInstance(jasperReportsContext).fill(compiled, new HashMap<>());
Now your repository must extend default one to be hack-injected(cause of hodgie coded "isAssignableFrom") successfully
public class PrintFormsRepositoryService extends DefaultRepositoryService {
#Override
public InputStream getInputStream(RepositoryContext context, String uri) {
// return here your own good simple poj inputStream even from memory if you found source
// or pass to another repository service(default one probably)
return null;
}
}

MEF exports that require remote data (like DB data) in order to be created

please excuse the long description at the beginning. the questions are at the end.
i have a windows service that is supposed to read data form some data sources (represented by the IDataSource interface).
i'm using MEF in my project and i was thinking of injecting the required data sources via ctor injection like below:
[Export(typeof(Service))]
public class Service:ServiceBase{
[ImportingConstructor]
public Service([ImportMany]IEnumerable<IDataSource> dataSources){
//...
}
}
However, there is a problem in doing it like this. The service needs to use any combination of data sources: multiple data sources of the same type (ex: 2 CSVDataSource instances) or multiple data sources of different types (ex: 2 CSVDataSource instances and 1 SQLDataSource instance).
Each data source has properties that are retrieved from the DB in order to properly set it up. these settings might indicate from where to read the data and at what intervals. this is why, in my implementation, the data sources have a ctor that accepts an id. this id is used to identify the data source in the DB and to retrieve the specific data source settings from the DB. this can be seen below.
public class CSVDataSource: IDataSource{
public CSVDataSource(int dsId){
//call web service in order to get properties to
//properly set up the data source.
}
//...
}
i feel that the service definition presented above is not suited for this scenario. The other approach I can think of is to use some sort of factory that allows the service to dynamically create the data sources inside. this implementation might look like below.
public class Service:ServiceBase{
[ImportingConstructor]
public Service(IDataSourceFactory dsFactory)
{
if (dsFactory == null) throw new ArgumentNullException("dsFactory");
IEnumerable<IDataSource> dataSources = dsFactory.CreateAll();
}
}
[Export(typeof(IDataSourceFactory))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class DataSourceFactory:IDataSourceFactory
{
private readonly int agentId;
[ImportingConstructor]
public DataSourceFactory([Import("AgentId")]int agentId)
{
this.agentId = agentId;
}
public IEnumerable<IDataSource> CreateAll()
{
List<IDataSource> dataSources = new List<IDataSource>();
//access web service and instantiate the data sources
return dataSources;
}
}
And now to my questions:
is my factory approach a good ideea or should i look for another approach?
is it ok to have exports that require data from a remote location in order to be created?
Did you come across ExportMetadataAttribute before? It will allow you to assign metadata to an export that you can view before the export is created. You'll be able to import your IDataSources as Lazy and then should be able to create them yourself with the required parameters.
There's a good breakdown of Lazy and ExportMetadata here

EntityFramework with Repository Pattern and no Database

I have a web api project that I'm building on an N-Tier system. Without causing too many changes to the overall system, I will not be touching the data server that has access to the database. Instead, I'm using .NET remoting to create a tcp channel that will allow me to send requests to the data server, which will then query the database and send back a response object.
On my application, I would like to use entity framework to create my datacontexts (unit of work), then create a repository pattern that interfaces with those contexts, which will be called by the web api project that I created.
However, I'm having problems with entity framework as it requires me to have a connection with the database. Is there anyway I can create a full entity framework project without any sqlconnections to the database? I just need dbcontexts, which I will be mapping my response objects and I figure that EF would do what I needed (ie help with design, and team collabs, and provide a nice graphical designer); but it throws an error insisting that I need a connection string.
I've been searching high and low for tutorials where a database is not needed, nor any sql connection string (this means no localdb either).
Okay as promised, I have 3 solutions for this. I personally went with #3.
Note: Whenever there is a repository pattern present, and "datacontext" is used, this is interpreted as your UnitOfWork.
Solution 1: Create singletons to represent your datacontext.
http://www.breezejs.com/samples/nodb
I found this idea after going to BreezeJS.com's website and checked out their samples. They have a sample called NoDb, which allows them to create a singleton, which can create an item and a list of items, and a method to populate the datacontext. You create singletons that would lock a space in memory to prevent any kind of thread conflicts. Here is a tid bit of the code:
//generates singleton
public class TodoContext
{
static TodoContext{ }
private TodoContext() { }
public static TodoContext Instance
{
get
{
if (!__instance._initialized)
{
__instance.PopulateWithSampleData();
__instance._initialized = true;
}
return __instance;
}
}
public void PopulateWithSampleData()
{
var newList = new TodoItem { Title = "Before work"};
AddTodoList(newList);
var listId = newList.TodoListId;
var newItem = new TodoItem {
TodoListId = listId, Title = "Make coffee", IsDone = false };
AddTodoItem(newItem);
newItem = new TodoItem {
TodoListId = listId, Title = "Turn heater off", IsDone = false };
AddTodoItem(newItem);
}
//SaveChanges(), SaveTodoList(), AddTodoItem, etc.
{ ... }
private static readonly Object __lock = new Object();
private static readonly TodoContext __instance = new TodoContext();
private bool _initialized;
private readonly List<TodoItem> _todoLists = new List<TodoItem>();
private readonly List<KeyMapping> _keyMappings = new List<KeyMapping>();
}
There's a repository included which directs how to save the context and what needs to be done before the context is saved. It also allows the list of items to be queryable.
Problem I had with this:
I felt like there was higher maintenance when creating new datacontexts. If I have StateContext, CityContext, CountryContext, the overhead of creating them would be too great. I'd have problems trying to wrap my head around relating them to each other as well. Plus I'm not too sure how many people out there who agree with using singletons. I've read articles that we should avoid singletons at all costs. I'm more concerns about anyone who'd be reading this much code.
Solution 2: Override the Seed() for DropCreateDatabaseAlways
http://www.itorian.com/2012/10/entity-frameworks-database-seed-method.html
For this trick, you have to create a class called SampleDatastoreInitializer that inherits from System.Data.Entity.DropCreateDatabaseAlways where T is the datacontext, which has a reference to a collection of your POCO model.
public class State
{
[Key()]
public string Abbr{ get; set; }
public string Name{ get; set; }
}
public class StateContext : DbContext
{
public virtual IDbSet<State> States { get; set; }
}
public class SampleDatastoreInitializer : DropCreateDatabaseAlways<StateContext>
{
protected override void Seed (StateContext context)
{
var states = new List<State>
{
new State { Abbr = "NY", Name = "New York" },
new State { Abbr = "CA", Name = "California" },
new State { Abbr = "AL", Name = "Alabama" },
new State { Abbr = "Tx", Name = "Texas" },
};
states.ForEach(s => context.States.Add(s));
context.SaveChanges();
}
}
This will actually embed the data in a cache, the DropCreateDatabaseAlways means that it will drop the cache and recreate it no matter what. If you use some other means of IDatabaseInitializer, and your model has a unique key, you might get an exception error, where you run it the first time, it works, but run it again and again, it will fail because you're violating the constraints of primary key (since you're adding duplicate rows).
Problem I had with this:
This seems like it should only be used to provide sample data when you're testing the application, not for production level. Plus I'd have to continously create a new initializer for each context, which plays a similar problem noted in solution 1 of maintainability. There is nothing automatic happening here. But if you want a way to inject sample code without hooking up to a database, this is a great solution.
Solution 3: Entity framework with Repository (In-memory persistence)
I got this solution from this website:
http://www.roelvanlisdonk.nl/?p=2827
He first sets up an edmx file, using EF5 and the code generator templates for EF5 dbcontexts you can get from VS extension libraries.
He first uses the edmx to create the contexts and changes the tt templates to bind to the repository class he made, so that the repository will keep track of the datacontext, and provide the options of querying and accessing the data through the repository; in his website though he calls the repository as MemoryPersistenceDbSet.
The templates he modified will be used to create datacontexts that will bind to an interface (IEntity) shared by all. Doing it this way is nice because you are establishing a Dependency Injection, so that you can add any entity you want through the T4 templates, and there'd be no complaints.
Advantage of this solution:
Wrapping up the edmx in repository pattern allows you to leverage the n-tier architecture, so that any changes done to the backend won't affect the front end, and allows you to separate the interface between the front end and backend so there are no coupled dependencies. So maybe later on, I can replace my edmx with petapoco, or massive, or some other ORM, or switch from in-memory persistence to fetching data from a database.
I followed everything exactly as explained. I made one modification though:
In the t4 template for .Context.tt, where DbSetInConstructor is added, I had the code written like this:
public string DbSetInConstructor(EntitySet entitySet)
{
return string.Format(
CultureInfo.InvariantCulture,
“this.{1} = new BaseRepository();”,
_typeMapper.GetTypeName(entitySet.ElementType), entitySet);
}
Because in my case I had the entityset = Persons and entityname = Person. So there’d be discrepancy. But this should cover all bases.
Final step:
So whether you picked solution 1, 2, or 3. You have a method to automatically populate your application. In these cases, the stubs are embedded in the code. In my case, what I've done is have my web server (containing my front end app), contact my data server, have the data server query the database. The data server will receive a dataset, serialize it, and pass it back to the web server. The web server will take that dataset, deserialize it, and auto-map to an object collection (list, or enumberable, or objectcollection, etc).
I would post the solutions more fully but there's way too much detail between all 3 of these solutions. Hopefully these solutions would point anyone in the right direction.
Dependency Injection
If anyone wants some information about how to allow DI to api controllers, Peter Provost provides a very useful blog that explains how to do it. He does a very very good job.
http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api/
few more helpful links of repository wrapping up edmx:
http://blogs.msdn.com/b/wriju/archive/2013/08/23/using-repository-pattern-in-entity-framework.aspx
http://www.codeproject.com/Articles/688929/Repository-Pattern-and-Unit-of

Axis2 How to create a service instance for other services

My service will load a lot of data (from txt files) to memory every request.
But,I want to keep the data in memory.
Because it is read from same txt files.
public class pirTMain {
public String[] RUN_pirT(...){
...
//this object will read txt files to initialize
ELC elc = new ELC(elcFolder.getPath());
//use elc to initialize a graph
pirT.initGraph(userID, nodeFile.getPath(), userScore, elc, true, begin, target);
//Use graph to search paths
itinerary = pirT.search(userID, TopK, begin, beginWithTime, target, targetWithTime);
...
I had read Axis2 document.
It says I can change service scope to "application".
But I still don't know how to do it, because I use eclipse plugin to generate a web service *.arr.
Can anyone suggest me how to separate elc object to another service?
Then, my pirTMain class can use it.
pirTMain is 'request'.
elc is 'application'.
thanks a lot.
There are a lot of different ways to achieve this, the simplest one that comes in my mind is to create a static reference to the read lines so that it's shared among all threads in the same virtual machine:
#WebService
public MyServiceClass {
private static String[] readLines = null;
private static synchronized getLines(){
if (readLines == null)
readLines = ....;
return readLines;
}
public int getNumberOfLines(){
return MyServiceClass.getLines().length;
}
public String getLine(int position){
return MyServiceClass.getLines()[position];
}
...
}
Probably not the "cleanest" way, but it works and it's easy to do. You could also wrap the login in a more standard "singleton pattern" if you prefer. keep in mind that getLines should be synchronized to be thread safe but if you experience bottlenecks remove the synchronized keyword, you could get useless reads on first calls but it would be faster.

Dynamic mask data for web project

Currently our web projects need to anonymize some data.
(for example a security number like 432-55-1111 might appear as 432-55-**)
These datas may contain email, id, price, date ,and so on.
The tables' name and columns that needed to be masked was saved in DB.
We are using spring security to judge a user whether he can see the data or not.
The data domain object(CMP) may be get from SQL or JPQL(named query or native query)or JPA Load method or Mainframe.
We need to find a best efficient way (not the DB end) to mask these data dynamically.
If we use a interceptor at the EJB method end , we need to annotation all the Object(DTO)
and all the columns. That's may be low efficiency.
Any body know how can we invoke a method(like a interceptor) when finish SQL executed and named query(native query) exectued, and we can call a method to mask the result by the query and user id.
Or other ways.
It would be good to have this in the lowest level, so that other applications like reporting would not need a separate solution.
Our project's architecture is JSF+Spring+EJB 3.0+JPA 1.0.We have many web projects.For JPA some projects using EclipseLink 2.2 ,some using Hibernate.
UPDATE:
More information about our projects. We have many web project about different feature.So we have many ejb projects associated with them. Every ejb has DAO to get their CMP by call JPQL or get(class, primarykey) metod.Like below:
Query query = em.createNamedQuery(XXXCMP.FIND_XXX_BY_NAME);
query.setHint(QueryHints.READ_ONLY, HintValues.TRUE);
query.setParameter("shortName", "XXX").getSingleResult();
Or
XXXCMP screen = entityManager.find(XXXCMP.class, id);
The new EJB services code converter to transfrom the data from CMP to DTO.
The converter as below:
/**
* Convert to CMP.
*
*/
CMP convertToCMP(DTO dto, EntityManager em);
/**
* Convert CMP to domain object with all fields populated, the default scenario is
* <code>EConvertScenario.Detail</code>.
*
*/
DTO convertFromCMP(CMP cmp, EntityManager em);
But some old services use their own methods to convert CMP.Also some domain services used for search lazy paing, they also don't use the converter.
We want to mask the data before the CMP convert to DTO.
You can try EntityListener to intercept entity loading into the persistence context with #PostLoad annotation.
Else, can try within accesor methods(getter/setter) which I think is suitable for masking/formatting etc.
Edit : (based on comments & question update)
You can share entity/DTO across appications
public String getSomethingMasked(){
return mask(originalString);
}
The data retrieval pattern isn't uniform across applications. If all the applications are using same database, it must be generalized. There is no point of writing same thing again with different tools. Each application might apply business logic afterwards.
Probably, you can have a separate project meant for interacting with database & then including it in other applications for further use. So it will be a common point to change anything, debug, enhance etc.
You are using Eclipselink, Hibernate & other custom ways for fetching data & you require minimal workaround, which from my perspective seems difficult.
Either centralize the data retrieval or make changes all over separately if possible, which I think is not feasible, compromising consistency.
In this case, you may intercept the JSF's conversion fase. This solution applies to JSF views, not to reportings.
#FacesConverter("AnonymizeDataConverter")
public class AnonymizeDataConverter implements Converter{
#Override
public Object getAsObject(FacesContext context, UIComponent component,
String value) {
return getAnonymisedData(value);
}
#Override
public String getAsString(FacesContext context, UIComponent component,
Object value) {
return getAnonymisedData(value);
}
public static String getAnonymisedData(Object data) {
if (data == null)
return "";
String value = data.toString().trim();
if (!value.isEmpty())
return value.substring(0, value.lenght() - 4) + "**";
return "";
}
}