diff --git a/README.md b/README.md index ca2c6fcee..800efa4f5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # Design pattern samples in Java. ## Build status: @@ -62,6 +61,13 @@ Behavioral patterns are concerned with algorithms and the assignment of responsi * [Callback](#callback) * [Execute Around](#execute-around) +### Presentation Tier Patterns + +Presentation Tier patterns are the top-most level of the application, this is concerned with translating tasks and results to something the user can understand. + +* [Intercepting Filter](#intercepting-filter) + + ## Abstract Factory [↑](#list-of-design-patterns) **Intent:** Provide an interface for creating families of related or dependent objects without specifying their concrete classes. @@ -431,6 +437,17 @@ Behavioral patterns are concerned with algorithms and the assignment of responsi **Applicability:** Use the Callback pattern when * When some arbitrary synchronous or asynchronous action must be performed after execution of some defined activity. + +## Intercepting Filter [↑](#list-of-design-patterns) +**Intent:** Provide pluggable filters to conduct necessary pre-processing and post-processing to requests from a client to a target + +![alt text](https://github.com/iluwatar/java-design-patterns/blob/master/intercepting-filter/etc/Intercepting-filter.png "Intercepting Filter") + +**Applicability:** Use the Intercepting Filter pattern when +* a system uses pre-processing or post-processing requests +* a system should do the authentication/ authorization/ logging or tracking of request and then pass the requests to corresponding handlers +* you want a modular approach to configuring pre-processing and post-processing schemes + **Real world examples:** * [CyclicBarrier] (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html#CyclicBarrier%28int,%20java.lang.Runnable%29) constructor can accept callback that will be triggered every time when barrier is tripped. @@ -453,6 +470,7 @@ Behavioral patterns are concerned with algorithms and the assignment of responsi **Real world examples:** * [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) prototype inheritance + # Frequently asked questions **Q: What is the difference between State and Strategy patterns?** @@ -476,7 +494,7 @@ The difference is the intent of the patterns. While Proxy controls access to the 1. Fork the repository. 2. Implement the code changes in your fork. Remember to add sufficient comments documenting the implementation. 3. Create a simple class diagram from your example code. -4. Add description of the pattern in README.md and link to the class diagram. +4. Add description of the pattern in README.md and link to the class diagram. 5. Create a pull request. **For creating/editing UML diagrams** you need one of the following: @@ -497,10 +515,13 @@ The difference is the intent of the patterns. While Proxy controls access to the * [Let’s Modify the Objects-First Approach into Design-Patterns-First](http://edu.pecinovsky.cz/papers/2006_ITiCSE_Design_Patterns_First.pdf) * [Pattern Languages of Program Design](http://www.amazon.com/Pattern-Languages-Program-Design-Coplien/dp/0201607344/ref=sr_1_1) * [Martin Fowler - Event Aggregator](http://martinfowler.com/eaaDev/EventAggregator.html) +* [TutorialsPoint - Intercepting Filter](http://www.tutorialspoint.com/design_pattern/intercepting_filter_pattern.htm) +* [Presentation Tier Pattern](http://www.javagyan.com/tutorials/corej2eepatterns/presentation-tier-patterns) * [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](http://www.amazon.com/Functional-Programming-Java-Harnessing-Expressions/dp/1937785467/ref=sr_1_1) + # License This project is licensed under the terms of the MIT license. diff --git a/intercepting-filter/etc/Intercepting-filter.png b/intercepting-filter/etc/Intercepting-filter.png new file mode 100644 index 000000000..5a97db09c Binary files /dev/null and b/intercepting-filter/etc/Intercepting-filter.png differ diff --git a/intercepting-filter/pom.xml b/intercepting-filter/pom.xml new file mode 100644 index 000000000..19ebdfbe2 --- /dev/null +++ b/intercepting-filter/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.0-SNAPSHOT + + intercepting-filter + + + junit + junit + test + + + diff --git a/intercepting-filter/src/main/java/com/iluwatar/AddressFilter.java b/intercepting-filter/src/main/java/com/iluwatar/AddressFilter.java new file mode 100644 index 000000000..e99185e26 --- /dev/null +++ b/intercepting-filter/src/main/java/com/iluwatar/AddressFilter.java @@ -0,0 +1,14 @@ +package com.iluwatar; +/** + * Concrete implementation of filter + * This filter is responsible for checking/filtering the input in the address field, returns null if field is empty + * @author joshzambales + * + */ +public class AddressFilter implements Filter{ + public String execute(String[] request){ + if(request[2].equals("")){ + return null; + }else return request[2]; + } +} \ No newline at end of file diff --git a/intercepting-filter/src/main/java/com/iluwatar/App.java b/intercepting-filter/src/main/java/com/iluwatar/App.java new file mode 100644 index 000000000..af22d9ec3 --- /dev/null +++ b/intercepting-filter/src/main/java/com/iluwatar/App.java @@ -0,0 +1,35 @@ +package com.iluwatar; +import java.util.*; +import javax.swing.*; +import javax.swing.table.*; +import java.awt.*; +import java.awt.event.*; +/** + * + * This is an app that checks whether the order request is valid through pre-processing done via Filters + * Each field has its own corresponding Filter + * @author joshzambales + * + */ +public class App{ + public static void main(String[] args){ + FilterManager filterManager = new FilterManager(new Target()); + filterManager.setFilter(new NameFilter()); + filterManager.setFilter(new ContactFilter()); + filterManager.setFilter(new AddressFilter()); + filterManager.setFilter(new DepositFilter()); + filterManager.setFilter(new OrderFilter()); + + Client client = new Client(); + client.setFilterManager(filterManager); + } +} + + + + + + + + + diff --git a/intercepting-filter/src/main/java/com/iluwatar/Client.java b/intercepting-filter/src/main/java/com/iluwatar/Client.java new file mode 100644 index 000000000..a3bd2137f --- /dev/null +++ b/intercepting-filter/src/main/java/com/iluwatar/Client.java @@ -0,0 +1,90 @@ +package com.iluwatar; + import java.util.*; +import javax.swing.*; +import javax.swing.table.*; +import java.awt.*; +import java.awt.event.*; + +/** + * The Client class is responsible for handling the input and running them through filters inside the filterManager + * + * This is where Filters come to play as the client pre-processes the request before being displayed in the Target + * + * @author joshzambales + * + */ +public class Client extends JFrame{ + private FilterManager filterManager; + private JLabel jl; + private JTextField[] jtFields; + private JTextArea[] jtAreas; + private JButton clearButton, processButton; + public Client(){ + super("Client System"); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setSize(300,300); + jl = new JLabel("RUNNING..."); + jtFields = new JTextField[3]; + for(int i = 0; i < 3; i++){ + jtFields[i] = new JTextField(); + } + jtAreas = new JTextArea[2]; + for(int i = 0; i < 2; i++){ + jtAreas[i] = new JTextArea(); + } + clearButton = new JButton("Clear"); + processButton = new JButton("Process"); + + setup(); + } + private void setup(){ + setLayout(new BorderLayout()); + JPanel panel = new JPanel(); + add(jl,BorderLayout.SOUTH); + add(panel, BorderLayout.CENTER); + panel.setLayout(new GridLayout(6,2)); + panel.add(new JLabel("Name")); + panel.add(jtFields[0]); + panel.add(new JLabel("Contact Number")); + panel.add(jtFields[1]); + panel.add(new JLabel("Address")); + panel.add(jtAreas[0]); + panel.add(new JLabel("Deposit Number")); + panel.add(jtFields[2]); + panel.add(new JLabel("Order")); + panel.add(jtAreas[1]); + panel.add(clearButton); + panel.add(processButton); + + clearButton.addActionListener(new ActionListener(){ + @Override + public void actionPerformed(ActionEvent e){ + for(JTextArea i : jtAreas){ + i.setText(""); + } + for(JTextField i : jtFields){ + i.setText(""); + } + } + }); + + processButton.addActionListener(new ActionListener(){ + @Override + public void actionPerformed(ActionEvent e){ + String request = String.format("%s&%s&%s&%s&%s",jtFields[0].getText(),jtFields[1].getText(),jtAreas[0].getText(),jtFields[2].getText(),jtAreas[1].getText()); + + jl.setText(sendRequest(request)); + } + }); + + JRootPane rootPane = SwingUtilities.getRootPane(processButton); + rootPane.setDefaultButton(processButton); + setVisible(true); + } + public void setFilterManager(FilterManager filterManager){ + this.filterManager = filterManager; + } + public String sendRequest(String request){ + return filterManager.filterRequest(request); + } +} \ No newline at end of file diff --git a/intercepting-filter/src/main/java/com/iluwatar/ContactFilter.java b/intercepting-filter/src/main/java/com/iluwatar/ContactFilter.java new file mode 100644 index 000000000..30cb34953 --- /dev/null +++ b/intercepting-filter/src/main/java/com/iluwatar/ContactFilter.java @@ -0,0 +1,14 @@ +package com.iluwatar; +/** + * Concrete implementation of filter + * This filter checks for the contact field in which it checks if the input consist of numbers and it also checks if the input follows the length constraint (11 digits) + * @author joshzambales + * + */ +public class ContactFilter implements Filter{ + public String execute(String[] request){ + if(request[1].equals("") || request[1].matches(".*[^\\d]+.*") || request[1].length() != 11){ + return null; + }else return request[1]; + } +} \ No newline at end of file diff --git a/intercepting-filter/src/main/java/com/iluwatar/DepositFilter.java b/intercepting-filter/src/main/java/com/iluwatar/DepositFilter.java new file mode 100644 index 000000000..76bfb9a1a --- /dev/null +++ b/intercepting-filter/src/main/java/com/iluwatar/DepositFilter.java @@ -0,0 +1,15 @@ +package com.iluwatar; +/** + * Concrete implementation of filter +* + * This checks for the deposit code, returns null when deposit field is empty + * @author joshzambales + * + */ +public class DepositFilter implements Filter{ + public String execute(String[] request){ + if(request[3].equals("")){ + return null; + }else return request[3]; + } +} diff --git a/intercepting-filter/src/main/java/com/iluwatar/Filter.java b/intercepting-filter/src/main/java/com/iluwatar/Filter.java new file mode 100644 index 000000000..f127f79a8 --- /dev/null +++ b/intercepting-filter/src/main/java/com/iluwatar/Filter.java @@ -0,0 +1,11 @@ +package com.iluwatar; +/** +* Filter interface + * Filters perform certain tasks prior or after execution of request by request handler. + * In this case, before the request is handled by the target, the request undergoes through each Filter + * @author joshzambales + * + */ +public interface Filter{ + public String execute(String[] request); +} diff --git a/intercepting-filter/src/main/java/com/iluwatar/FilterChain.java b/intercepting-filter/src/main/java/com/iluwatar/FilterChain.java new file mode 100644 index 000000000..09ca6598f --- /dev/null +++ b/intercepting-filter/src/main/java/com/iluwatar/FilterChain.java @@ -0,0 +1,49 @@ + package com.iluwatar; + import java.util.*; +/** + * Filter Chain carries multiple filters and help to execute them in defined order on target. + * + * @author joshzambales + */ +public class FilterChain{ + private ArrayList filters = new ArrayList(); + private final Target target; + + public FilterChain(Target target){ + this.target = target; + } + public void addFilter(Filter filter){ + filters.add(filter); + } + + public String execute(String request){ + String tempout[] = new String[filters.size()]; + + String tempin[] = request.split("&"); + int i = 0; + try{ + for(Filter filter:filters){ + tempout[i] = null; + tempout[i++] = filter.execute(tempin); + } + }catch(Exception e){ + return "NOT ENOUGHT INPUT"; + } + + if(tempout[4] == null){ + return "INVALID ORDER!"; + }else if(tempout[3] == null){ + return "INVALID DEPOSIT NUMBER!"; + }else if(tempout[2] == null){ + return "INVALID ADRDESS!"; + }else if(tempout[1] == null){ + return "INVALID Contact Number!"; + }else if(tempout[0] == null){ + return "INVALID Name!"; + }else{ + target.execute(tempout); + return "RUNNING..."; + } + } + +} diff --git a/intercepting-filter/src/main/java/com/iluwatar/FilterManager.java b/intercepting-filter/src/main/java/com/iluwatar/FilterManager.java new file mode 100644 index 000000000..25b98730b --- /dev/null +++ b/intercepting-filter/src/main/java/com/iluwatar/FilterManager.java @@ -0,0 +1,24 @@ + package com.iluwatar; + import java.util.*; +import javax.swing.*; +import javax.swing.table.*; +import java.awt.*; +import java.awt.event.*; +/** + * Filter Manager manages the filters and Filter Chain. + * @author joshzambales + * + */ +public class FilterManager{ + private FilterChain filterChain; + + public FilterManager(Target target){ + filterChain = new FilterChain(target); + } + public void setFilter(Filter filter){ + filterChain.addFilter(filter); + } + public String filterRequest(String request){ + return filterChain.execute(request); + } +} \ No newline at end of file diff --git a/intercepting-filter/src/main/java/com/iluwatar/NameFilter.java b/intercepting-filter/src/main/java/com/iluwatar/NameFilter.java new file mode 100644 index 000000000..de929fc24 --- /dev/null +++ b/intercepting-filter/src/main/java/com/iluwatar/NameFilter.java @@ -0,0 +1,14 @@ +package com.iluwatar; +/** + * Concrete implementation of filter + * This filter checks if the input in the Name field is valid. (alphanumeric) + * @author joshzambales + * + */ +public class NameFilter implements Filter{ + public String execute(String[] request){ + if(request[0].equals("") || request[0].matches(".*[^\\w|\\s]+.*")){ + return null; + }else return request[0]; + } +} \ No newline at end of file diff --git a/intercepting-filter/src/main/java/com/iluwatar/OrderFilter.java b/intercepting-filter/src/main/java/com/iluwatar/OrderFilter.java new file mode 100644 index 000000000..e33dcd1c6 --- /dev/null +++ b/intercepting-filter/src/main/java/com/iluwatar/OrderFilter.java @@ -0,0 +1,15 @@ +package com.iluwatar; +/** + * Concrete implementation of filter + * This checks for the order field, returns null when order field is empty + * + * @author joshzambales + * + */ +public class OrderFilter implements Filter{ + public String execute(String[] request){ + if(request[4].equals("")){ + return null; + }else return request[4]; + } +} \ No newline at end of file diff --git a/intercepting-filter/src/main/java/com/iluwatar/Target.java b/intercepting-filter/src/main/java/com/iluwatar/Target.java new file mode 100644 index 000000000..9068de95f --- /dev/null +++ b/intercepting-filter/src/main/java/com/iluwatar/Target.java @@ -0,0 +1,59 @@ + package com.iluwatar; + import java.util.*; +import javax.swing.*; +import javax.swing.table.*; +import java.awt.*; +import java.awt.event.*; +/** + * This is where the requests are displayed after being validated by filters. + * + * @author mjoshzambales + * + */ +public class Target extends JFrame{ + private JTable jt; + private JScrollPane jsp; + private DefaultTableModel dtm; + private JButton del; + public Target(){ + super("Order System"); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setSize(640,480); + dtm = new DefaultTableModel(new Object[]{"Name", "Contact Number", "Address", "Deposit Number", "Order"},0); + jt = new JTable(dtm); + del = new JButton("Delete"); + setup(); + } + private void setup(){ + setLayout(new BorderLayout()); + JPanel bot = new JPanel(); + add(jt.getTableHeader(), BorderLayout.NORTH); + bot.setLayout(new BorderLayout()); + bot.add(del, BorderLayout.EAST); + add(bot, BorderLayout.SOUTH); + jsp = new JScrollPane(jt); + jsp.setPreferredSize(new Dimension(500,250)); + add(jsp, BorderLayout.CENTER); + + del.addActionListener(new DListener()); + + JRootPane rootPane = SwingUtilities.getRootPane(del); + rootPane.setDefaultButton(del); + setVisible(true); + } + public void execute(String[] request){ + dtm.addRow(new Object[]{request[0],request[1],request[2],request[3],request[4]}); + } + + class DListener implements ActionListener{ + @Override + public void actionPerformed(ActionEvent e){ + int temp = jt.getSelectedRow(); + if(temp == -1) return; + int temp2 = jt.getSelectedRowCount(); + for(int i = 0; i < temp2; i++){ + dtm.removeRow(temp); + } + } + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 72c37c3ed..d81be42c9 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,7 @@ callback execute-around property + intercepting-filter