I have a layer, call it Service and another called Permission. I was wondering if I could enforce a rule that says:
From within any public method of any public class within Service layer whose parameter list contains a parameter named foo, assert that it calls a method from Permission layer (and ideally, ensure it is called before anything else within the Service layer).
Is this possible with ArchUnit?
It does not work out of the box but you can achieve that goal with the following solution:
DescribedPredicate<JavaClass> isPermissionClass = JavaClass.Predicates
.resideInAnyPackage("..permission..");
classes()
.that().resideInAnyPackage("..service..")
.should(new ContainOnlyMethodsCallingPermissionClass(isPermissionClass));
ContainOnlyMethodsCallingPermissionClass can be defined as follows. It first collects all declared methods and then checks whether outgoing method calls to permission classes cover all collected methods.
public static class ContainOnlyMethodsCallingPermissionClass extends ArchCondition<JavaClass> {
private final DescribedPredicate<JavaClass> isPermissionClass;
public ContainOnlyMethodsCallingPermissionClass(DescribedPredicate<JavaClass> isPermissionClass) {
super("only contain methods calling a permission class");
this.isPermissionClass = isPermissionClass;
}
#Override
public void check(JavaClass javaClass, ConditionEvents events) {
Set<String> methodIdentifiers = getMethodIdentifiersOfClass(javaClass);
methodIdentifiers.removeAll(collectMethodsCallingPermissionClass(javaClass));
for (String methodId : methodIdentifiers) {
events.add(new SimpleConditionEvent(javaClass, false, methodId));
}
}
private Set<String> collectMethodsCallingPermissionClass(JavaClass javaClass) {
Set<String> methodIdentifiers = new HashSet<>();
for (JavaAccess<?> access : javaClass.getAccessesFromSelf()) {
if (!isCallFromMethod(access)) {
continue;
}
if (isMethodCallToPermissionClass(access)) {
JavaMethod callingMethod = (JavaMethod) access.getOwner();
methodIdentifiers.remove(callingMethod.getFullName());
}
}
return methodIdentifiers;
}
private Set<String> getMethodIdentifiersOfClass(JavaClass javaClass) {
return javaClass.getMethods().stream().filter(method -> !method.isConstructor())
.map(method -> method.getFullName()).collect(Collectors.toSet());
}
private boolean isCallFromMethod(JavaAccess<?> access) {
return access.getOrigin() instanceof JavaMethod;
}
private boolean isMethodCallToPermissionClass(JavaAccess<?> access) {
return isPermissionClass.apply(access.getTargetOwner());
}
}
You can also change the predicate operating on JavaClasses to one operating on JavaMethodCalls for locating relevant permission methods more precisely. This additionally allows filtering out irrelevant methods in the service layer (e.g., toString() methods).
Related
I am creating a project that uses Entity framework Database first approach. The .edmx is currently generated and is in my data access layer project.
I have created a function import call GetAllTeam and corresponding complex type call TeamResult. I am trying to return the data to business layer by calling my function import, populating the complex type in the data access layer.
In my business layer I shall then map the complex type to business object and return to my web api. I would like to know if my approach is correct. Do I need to create a separate class project called entities with a class called team and then AutoMap that class with TeamResult the complex type and then return to the business layer or is it fine directly sending the TeamResult to the business layer.
Let me also know if there is any other issue with this approach.
Please see the code below
Data access layer:
public class TeamRepository
{
public IEnumerable<TeamResult> GetAllTeam()
{
using (var mcrContext = new MCREntities1())
{
return (from team in mcrContext.GetAllTeam()
select new TeamResult
{
TeamName = team.TeamName,
TeamDescription = team.TeamDescription,
Code = team.Code
}).ToList();
}
}
}
Business logic layer:
public class TeamService : ITeamService
{
private readonly ITeamRepository _teamRepository;
public TeamService(ITeamRepository teamRepository)
{
_teamRepository = teamRepository;
}
public IEnumerable<TeamDto> GetTeam()
{
IEnumerable<TeamResult> team = _teamRepository.GetAllTeam();
if (team != null)
{
foreach (var t in team)
{
yield return Mapper.Map<TeamDto>(t);
}
}
yield break;
}
}
public class DomainToDtoMapping : Profile
{
public DomainToDtoMapping()
{
CreateMap<TeamResult, TeamDto>().ReverseMap();
}
public override string ProfileName
{
get { return "DomainToDtoMapping"; }
}
}
Web Api:
public class TeamController : ApiController
{
private readonly ITeamService _teamServices;
public TeamController(ITeamService _teamServices)
{
_teamServices = teamServices;
}
public HttpResponseMessage Get()
{
var teams = _teamServices.GetTeam();
if (teams != null)
{
var teamEntities = teams as List<TeamDto> ?? teams.ToList();
if (teamEntities.Any())
return Request.CreateResponse(HttpStatusCode.OK, teamEntities);
}
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Team not found");
}
}
Personally, I think you are doing this just fine. Having another entity to map the stored procedure to before returning it from the repository wouldn't add any value because you are returning exactly what the stored procedure exposes already.
The business layer needs to know about any entities that the Repository can return and then map it to something to return later. This all looks good to me! :)
Let's say you have an order as an aggregate root. An order contains one or more line items.
It is my understanding that it's the repository's responsibility to instantiate an order object when asked.
The line items can be loaded at the time of the order object's creation (eager loaded), or the line item collection can be populated when it is accessed by the client code (lazy loaded).
If we are using eager loading, it's seems that the repository code would take responsibility with hydrating the line items when the order is created.
However if we are using lazy loading, how is the repository called when the LineItems collection is accessed without creating a dependency on the repository from the order domain class?
Main problem is in Repository's ability to get only aggregate roots (presenting aggregates), thus you cannot use Repository to get line items. This can lead to aggregate encapsulation violation.
I propose something like:
//Domain level:
public interface IOrderItemList {
IEnumerable<OrderItem> GetItems();
}
public class Order {
private IOrderItemList _orderItems;
public IEnumerable<OrderItem> OrderItems
{ get { return _orderItems.GetItems() } };
public Order(IOrderItemList orderItems)
{
_orderItems = orderItems;
}
}
public class OrderItemList : IOrderItemList
{
private IList<OrderItem> _orderItems;
public IEnumerable<OrderItem> GetItems() {
return _orderItems; //or another logic
}
//other implementation details
}
//Data level
public class OrderItemListProxy : IOrderItemList
{
//link to 'real' object
private OrderItemList _orderItemList;
private int _orderId;
//alternatively:
//private OrderEntity _orderEntity;
//ORM context
private DbContext _context;
public OrderItemListProxy(int orderId, DbContext context)
{
_orderId = orderId;
_context = context;
}
public IEnumerable<OrderItem> GetItems() {
if (_orderItemList == null)
{
var orderItemEntities = DbContext.Orders
.Single(order => order.Id == _orderId).OrderItems;
var orderItems = orderItemEntites.Select(...);
//alternatively: use factory to create OrderItem from OrderItemEntity
_orderItemList = new OrderItemList(orderItems);
}
return _orderItemList.GetItems();
}
}
public class OrderRepository
{
//ORM context
private DbContext _context;
Order GetOrder(int id)
{
var orderEntity = _context.Single(order => order.Id == id);
var order = new Order(new OrderItemListProxy(id, _context))
//alternatively:
//var order = new Order(new OrderItemListProxy(orderEntity, _context))
...
//init other fields
...
}
//other methods
...
}
Most important here is that IOrderItemList corresponds to domain layer, but OrderItemListProxy corresponds to data layer.
Finally,
You may use IList<OrderItem> instead of custom IOrderItemList or another appropriate interface.
Proxy implementation may differ.
I don't provide best practicies for using db context, it may depend on technologies you use.
My current implementation for service and business layer is straight forward as below.
public class MyEntity { }
// Business layer
public interface IBusiness { IList<MyEntity> GetEntities(); }
public class MyBusinessOne : IBusiness
{
public IList<MyEntity> GetEntities()
{
return new List<MyEntity>();
}
}
//factory
public static class Factory
{
public static T Create<T>() where T : class
{
return new MyBusinessOne() as T; // returns instance based on T
}
}
//Service layer
public class MyService
{
public IList<MyEntity> GetEntities()
{
return Factory.Create<IBusiness>().GetEntities();
}
}
We needed some changes in current implementation. Reason being data grew over the time and service & client cannot handle the volume of data. we needed to implement pagination to the current service. We also expect some more features (like return fault when data is more that threshold, apply filters etc), so the design needs to be updated.
Following is my new proposal.
public interface IBusiness
{
IList<MyEntity> GetEntities();
}
public interface IBehavior
{
IEnumerable<T> Apply<T>(IEnumerable<T> data);
}
public abstract class MyBusiness
{
protected List<IBehavior> Behaviors = new List<IBehavior>();
public void AddBehavior(IBehavior behavior)
{
Behaviors.Add(behavior);
}
}
public class PaginationBehavior : IBehavior
{
public int PageSize = 10;
public int PageNumber = 2;
public IEnumerable<T> Apply<T>(IEnumerable<T> data)
{
//apply behavior here
return data
.Skip(PageNumber * PageSize)
.Take(PageSize);
}
}
public class MyEntity { }
public class MyBusinessOne : MyBusiness, IBusiness
{
public IList<MyEntity> GetEntities()
{
IEnumerable<MyEntity> result = new List<MyEntity>();
this.Behaviors.ForEach(rs =>
{
result = rs.Apply<MyEntity>(result);
});
return result.ToList();
}
}
public static class Factory
{
public static T Create<T>(List<IBehavior> behaviors) where T : class
{
// returns instance based on T
var instance = new MyBusinessOne();
behaviors.ForEach(rs => instance.AddBehavior(rs));
return instance as T;
}
}
public class MyService
{
public IList<MyEntity> GetEntities(int currentPage)
{
List<IBehavior> behaviors = new List<IBehavior>() {
new PaginationBehavior() { PageNumber = currentPage, }
};
return Factory.Create<IBusiness>(behaviors).GetEntities();
}
}
Experts please suggest me if my implementation is correct or I am over killing it. If it correct what design pattern it is - Decorator or Visitor.
Also my service returns JSON string. How can I use this behavior collections to serialize only selected properties rather than entire entity. List of properties comes from user as request. (Kind of column picker)
Looks like I don't have enough points to comment on your question. So, I am gonna make some assumption as I am not a C# expert.
Assumption 1: Looks like you are getting the data first and then applying the pagination using behavior object. If so, this is a wrong approach. Lets say there are 500 records and you are showing 50 records per fetch. Instead of simply fetching 50 records from DB, you are fetching 500 records for 10 times and on top of it you are adding a costly filter. DB is better equipped to do this job that C# or Java.
I would not consider pagination as a behavior with respect to the service. Its the behavior of the presentation layer. Your service should only worry about 'Data Granularity'. Looks like one of your customer wants all the data in one go and others might want a subset of that data.
Option 1: In DAO layer, have two methods: one for pagination and other for regular fetch. Based on the incoming params decide which method to call.
Option 2: Create two methods at service level. One for a small subset of data and the other for the whole set of data. Since you said JSON, this should be Restful service. Then based on the incoming URL, properly call the correct method. If you use Jersey, this should be easy.
In a service, new behaviors can be added by simply exposing new methods or adding new params to existing methods/functionalities (just make sure those changes are backward compatible). We really don't need Decorator or Visitor pattern. The only concern is no existing user should be affected.
Consider the following existing classes which uses MEF to compose Consumer.
public interface IProducer
{
void Produce();
}
[Export(typeof(IProducer))]
public class Producer : IProducer
{
public Producer()
{
// perform some initialization
}
public void Produce()
{
// produce something
}
}
public class Consumer
{
[Import]
public IProducer Producer
{
get;
set;
}
[ImportingConstructor]
public Consumer(IProducer producer)
{
Producer = producer;
}
public void DoSomething()
{
// do something
Producer.Produce();
}
}
However, the creation of Producer has become complex enough that it can no longer be done within the constructor and the default behavior no longer suffices.
I'd like to introduce a factory and register it using a custom FactoryAttribute on the producer itself. This is what I have in mind:
[Export(typeof(IProducer))]
[Factory(typeof(ProducerFactory))]
public class Producer : IProducer
{
public Producer()
{
// perform some initialization
}
public void Produce()
{
// produce something
}
}
[Export]
public class ProducerFactory
{
public Producer Create()
{
// Perform complex initialization
return new Producer();
}
}
public class FactoryAttribute : Attribute
{
public Type ObjectType
{
get;
private set;
}
public FactoryAttribute(Type objectType)
{
ObjectType = objectType;
}
}
If I had to write the "new" code myself, it may very well look as follows. It would use the factory attribute, if it exists, to create a part, or default to the MEF to create it.
public object Create(Type partType, CompositionContainer container)
{
var attribute = (FactoryAttribute)partType.GetCustomAttributes(typeof (FactoryAttribute), true).FirstOrDefault();
if (attribute == null)
{
var result = container.GetExports(partType, null, null).First();
return result.Value;
}
else
{
var factoryExport = container.GetExports(attribute.ObjectType, null, null).First();
var factory = factoryExport.Value;
var method = factory.GetType().GetMethod("Create");
var result = method.Invoke(factory, new object[0]);
container.ComposeParts(result);
return result;
}
}
There are a number of articles how to implement a ExportProvider, including:
MEF + Object Factories using Export Provider
Dynamic Instantiation
However, the examples are not ideal when
The application has no dependencies or knowledge of Producer, only IProducer. It would not be able to register the factory when the CompositionContainer is created.
Producer is reused by several applications and a developer may mistakenly forget to register the factory when the CompositionContainer is created.
There are a large number of types that require custom factories and it may pose a maintenance nightmare to remember to register factories when the CompositionContainer is created.
I started to create a ExportProvider (assuming this would provide the means to implement construction using factory).
public class FactoryExportProvider : ExportProvider
{
protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition,
AtomicComposition atomicComposition)
{
// What to do here?
}
}
However, I'm having trouble understanding how to tell MEF to use the factory objects defined in the FactoryAttribute, and use the default creation mechanism if no such attribute exists.
What is the correct manner to implement this? I'm using MEF 2 Preview 5 and .NET 4.
You can make use of a property export:
public class ProducerExporter
{
[Export]
public IProducer MyProducer
{
get
{
var producer = new Producer();
// complex initialization here
return producer;
}
}
}
Note that the term factory isn't really appropriate for your example, I would reserve that term for the case where the importer wants to create instances at will, possibly by providing one or more parameters. That could be done with a method export:
public class ProducerFactory
{
[Export(typeof(Func<Type1,Type2,IProducer>)]
public IProducer CreateProducer(Type1 arg1, Type2 arg2)
{
return new Producer(arg1, arg2);
}
}
On the import side, you would then import a Func<Type1,Type2,IProducer> that you can invoke at will to create new instances.
I have a validation interface like so:
public interface IValidation<T> {
bool IsValid(T item, ref AggregateException fail);
}
I have a file importer that needs several validation interfaces
public FileImporter {
IEnumerable<IValidation<Patient>> Validators { get; set; }
public FileImporter(IWindsorContainer container) {
// the ResolveAll method does not do this
Validators = container.ResolveAll<IValidation<Patient>>("fileValidation");
}
}
I also have another class that has more validators but uses some of the same ones used in FileImporter.
public PatientService {
IEnumerable<IValidation<Patient>> Validators { get; set; }
public PatientService(IWindsorContainer container) {
// the ResolveAll method does not do this
Validators = container.ResolveAll<IValidation<Patient>>("userInputValidation");
}
}
For example I have two validators LastNameValidator and DateOfBirthValidator. LastNameValidator is used in both theFileImporterand thePatientService.DateOfBirthValidatoris only used in thePatientService` class. The implementation of these two classes are below the question.
My question is how can i wire up these two classes so that they are used as described above. And what method call should I make to resolve them?
public class LastNameValidator : IValidation<Patient> {
public bool IsValid(Patient p, ref AggregateException fail) {
var isValid = !string.IsNullOrWhitespace(p.LastName))
if (!isValid)
// update fail
return isValid;
}
}
public class DateOfBirthValidator : IValidation<Patient> {
public bool IsValid(Patient p, ref AggregateException fail) {
if (!p.DateOfBirth.HasValue) {
// update fail, can't be empty
return false;
}
if (p.DateOfBirth.Value > DateTime.Now) {
// update fail, can't be in future
return false;
}
return true;
}
}
I would consider the Typed Factory Facility. You could register your validators with the names "lastnamevalidator" and "dobvalidator". Then create a factory interface for grabbing those specific validators. You just need the interface -- the facility will do the implementation:
public interface IValidatorFactory
{
IValidator GetLastNameValidator();
IValidator GetDobValidator();
}
Now pass the IValidatorFactory to your component. This also removes the need to pass the Windsor container around (which isn't a good idea as it tightly couples your code to Windsor and makes unit testing more difficult).
Now just call the factory methods to access the particular validator each component needs.
UPDATE:
Still not clear on which part of your system is going to determine which IValidators to use, but maybe this would work. Use a marker inteface that is based on IValidator.
public interface IFileValidator : IValidator
{
}
public interface IUserInputValidator : IValidator
{
}
Now have your validators implement the marker interfaces depending on where they are going to be used -- and remember you can implement multiple interfaces so validators can be used in multiple situations. Example:
public class FileValidator : IFileValidator
{
public bool IsValid()
{
return false;
}
}
public class DobValidator : IUserInputValidator, IFileValidator
{
public bool IsValid()
{
return false;
}
}
public class LastNameValidator : IUserInputValidator
{
public bool IsValid()
{
return true;
}
}
Change the factory interface to return just the specific types of validators:
public interface IValidatorFactory
{
IFileValidator[] GetFileValidators();
IUserInputValidator[] GetUserInputValidators();
}
Now register the validators accorindg to their "type". If a validator has multiple uses, make sure to add a .Forward<> defintion for Windsor:
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<IValidatorFactory>().AsFactory(),
Component.For<IFileValidator>().ImplementedBy<FileValidator>(),
Component.For<IUserInputValidator>().ImplementedBy<LastNameValidator>(),
Component.For<IFileValidator>().Forward<IUserInputValidator>().ImplementedBy<DobValidator>()
);