diff --git a/.gitignore b/.gitignore index be3bc420c5..349efbcb67 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,7 @@ out/ .DS_Store # Maven -log/ +log/* target/ # Gradle @@ -83,4 +83,11 @@ jta/transaction-logs/ software-security/sql-injection-samples/derby.log spring-soap/src/main/java/com/baeldung/springsoap/gen/ /report-*.json -transaction.log \ No newline at end of file +transaction.log +*-shell.log + +apache-cxf/cxf-aegis/baeldung.xml +apache-fop/src/test/resources/input.xml +apache-fop/src/test/resources/output_herold.pdf +apache-fop/src/test/resources/output_html2fo.pdf +apache-fop/src/test/resources/output_jtidy.pdf \ No newline at end of file diff --git a/akka-http/README.md b/akka-http/README.md index 3831b5079f..ebe6581ff6 100644 --- a/akka-http/README.md +++ b/akka-http/README.md @@ -1,3 +1,7 @@ -## Relevant articles: +## Akka HTTP + +This module contains articles about Akka HTTP. + +### Relevant articles: - [Introduction to Akka HTTP](https://www.baeldung.com/akka-http) diff --git a/akka-streams/README.md b/akka-streams/README.md index 5f71991def..a59b7fde5c 100644 --- a/akka-streams/README.md +++ b/akka-streams/README.md @@ -1,3 +1,7 @@ +## Akka Streams + +This module contains articles about Akka Streams. + ### Relevant articles - [Guide to Akka Streams](https://www.baeldung.com/akka-streams) diff --git a/algorithms-genetic/README.md b/algorithms-genetic/README.md index 124e9c09e5..1c9e831ac2 100644 --- a/algorithms-genetic/README.md +++ b/algorithms-genetic/README.md @@ -1,4 +1,8 @@ -## Relevant articles: +## Genetic Algorithms + +This module contains articles about genetic algorithms. + +### Relevant articles: - [Introduction to Jenetics Library](https://www.baeldung.com/jenetics) - [Ant Colony Optimization](https://www.baeldung.com/java-ant-colony-optimization) diff --git a/algorithms-miscellaneous-1/README.md b/algorithms-miscellaneous-1/README.md index 57f5a5d478..25e2733538 100644 --- a/algorithms-miscellaneous-1/README.md +++ b/algorithms-miscellaneous-1/README.md @@ -1,9 +1,13 @@ -## Relevant articles: +## Algorithms - Miscellaneous + +This module contains articles about algorithms. Some classes of algorithms, e.g., [sorting](/../algorithms-sorting) and +[genetic algorithms](/../algorithms-genetic), have their own dedicated modules. + +### Relevant articles: - [Validating Input With Finite Automata in Java](https://www.baeldung.com/java-finite-automata) - [Example of Hill Climbing Algorithm](https://www.baeldung.com/java-hill-climbing-algorithm) -- [Monte Carlo Tree Search for Tic-Tac-Toe Game](https://www.baeldung.com/java-monte-carlo-tree-search) -- [Binary Search Algorithm in Java](https://www.baeldung.com/java-binary-search) - [Introduction to Minimax Algorithm](https://www.baeldung.com/java-minimax-algorithm) - [How to Calculate Levenshtein Distance in Java?](https://www.baeldung.com/java-levenshtein-distance) -- [How to Find the Kth Largest Element in Java](https://www.baeldung.com/java-kth-largest-element) \ No newline at end of file +- [How to Find the Kth Largest Element in Java](https://www.baeldung.com/java-kth-largest-element) +- More articles: [[next -->]](/../algorithms-miscellaneous-2) diff --git a/algorithms-miscellaneous-2/README.md b/algorithms-miscellaneous-2/README.md index 76727a1d4f..7560fc4fe7 100644 --- a/algorithms-miscellaneous-2/README.md +++ b/algorithms-miscellaneous-2/README.md @@ -1,4 +1,9 @@ -## Relevant articles: +## Algorithms - Miscellaneous + +This module contains articles about algorithms. Some classes of algorithms, e.g., [sorting](/../algorithms-sorting) and +[genetic algorithms](/../algorithms-genetic), have their own dedicated modules. + +### Relevant articles: - [Dijkstra Shortest Path Algorithm in Java](https://www.baeldung.com/java-dijkstra) - [Introduction to Cobertura](https://www.baeldung.com/cobertura) @@ -8,3 +13,4 @@ - [Create a Sudoku Solver in Java](https://www.baeldung.com/java-sudoku) - [Displaying Money Amounts in Words](https://www.baeldung.com/java-money-into-words) - [A Collaborative Filtering Recommendation System in Java](https://www.baeldung.com/java-collaborative-filtering-recommendations) +- More articles: [[<-- prev]](/../algorithms-miscellaneous-1) [[next -->]](/../algorithms-miscellaneous-3) diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/Graph.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/Graph.java new file mode 100644 index 0000000000..8145c03e7a --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/Graph.java @@ -0,0 +1,30 @@ +package com.baeldung.algorithms.astar; + +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + + +public class Graph { + private final Set nodes; + + private final Map> connections; + + public Graph(Set nodes, Map> connections) { + this.nodes = nodes; + this.connections = connections; + } + + public T getNode(String id) { + return nodes.stream() + .filter(node -> node.getId().equals(id)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("No node found with ID")); + } + + public Set getConnections(T node) { + return connections.get(node.getId()).stream() + .map(this::getNode) + .collect(Collectors.toSet()); + } +} diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/GraphNode.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/GraphNode.java new file mode 100644 index 0000000000..8d0539ead2 --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/GraphNode.java @@ -0,0 +1,5 @@ +package com.baeldung.algorithms.astar; + +public interface GraphNode { + String getId(); +} diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/RouteFinder.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/RouteFinder.java new file mode 100644 index 0000000000..35458093c5 --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/RouteFinder.java @@ -0,0 +1,66 @@ +package com.baeldung.algorithms.astar; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.stream.Collectors; + +public class RouteFinder { + private final Graph graph; + private final Scorer nextNodeScorer; + private final Scorer targetScorer; + + public RouteFinder(Graph graph, Scorer nextNodeScorer, Scorer targetScorer) { + this.graph = graph; + this.nextNodeScorer = nextNodeScorer; + this.targetScorer = targetScorer; + } + + public List findRoute(T from, T to) { + Map> allNodes = new HashMap<>(); + Queue openSet = new PriorityQueue<>(); + + RouteNode start = new RouteNode<>(from, null, 0d, targetScorer.computeCost(from, to)); + allNodes.put(from, start); + openSet.add(start); + + while (!openSet.isEmpty()) { + System.out.println("Open Set contains: " + openSet.stream().map(RouteNode::getCurrent).collect(Collectors.toSet())); + RouteNode next = openSet.poll(); + System.out.println("Looking at node: " + next); + if (next.getCurrent().equals(to)) { + System.out.println("Found our destination!"); + + List route = new ArrayList<>(); + RouteNode current = next; + do { + route.add(0, current.getCurrent()); + current = allNodes.get(current.getPrevious()); + } while (current != null); + + System.out.println("Route: " + route); + return route; + } + + graph.getConnections(next.getCurrent()).forEach(connection -> { + double newScore = next.getRouteScore() + nextNodeScorer.computeCost(next.getCurrent(), connection); + RouteNode nextNode = allNodes.getOrDefault(connection, new RouteNode<>(connection)); + allNodes.put(connection, nextNode); + + if (nextNode.getRouteScore() > newScore) { + nextNode.setPrevious(next.getCurrent()); + nextNode.setRouteScore(newScore); + nextNode.setEstimatedScore(newScore + targetScorer.computeCost(connection, to)); + openSet.add(nextNode); + System.out.println("Found a better route to node: " + nextNode); + } + }); + } + + throw new IllegalStateException("No route found"); + } + +} diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/RouteNode.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/RouteNode.java new file mode 100644 index 0000000000..842e50179d --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/RouteNode.java @@ -0,0 +1,67 @@ +package com.baeldung.algorithms.astar; + +import java.util.StringJoiner; + +class RouteNode implements Comparable { + private final T current; + private T previous; + private double routeScore; + private double estimatedScore; + + RouteNode(T current) { + this(current, null, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + } + + RouteNode(T current, T previous, double routeScore, double estimatedScore) { + this.current = current; + this.previous = previous; + this.routeScore = routeScore; + this.estimatedScore = estimatedScore; + } + + T getCurrent() { + return current; + } + + T getPrevious() { + return previous; + } + + double getRouteScore() { + return routeScore; + } + + double getEstimatedScore() { + return estimatedScore; + } + + void setPrevious(T previous) { + this.previous = previous; + } + + void setRouteScore(double routeScore) { + this.routeScore = routeScore; + } + + void setEstimatedScore(double estimatedScore) { + this.estimatedScore = estimatedScore; + } + + @Override + public int compareTo(RouteNode other) { + if (this.estimatedScore > other.estimatedScore) { + return 1; + } else if (this.estimatedScore < other.estimatedScore) { + return -1; + } else { + return 0; + } + } + + @Override + public String toString() { + return new StringJoiner(", ", RouteNode.class.getSimpleName() + "[", "]").add("current=" + current) + .add("previous=" + previous).add("routeScore=" + routeScore).add("estimatedScore=" + estimatedScore) + .toString(); + } +} diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/Scorer.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/Scorer.java new file mode 100644 index 0000000000..64eb1e546f --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/Scorer.java @@ -0,0 +1,5 @@ +package com.baeldung.algorithms.astar; + +public interface Scorer { + double computeCost(T from, T to); +} diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/HaversineScorer.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/HaversineScorer.java new file mode 100644 index 0000000000..97564ee154 --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/HaversineScorer.java @@ -0,0 +1,19 @@ +package com.baeldung.algorithms.astar.underground; + +import com.baeldung.algorithms.astar.Scorer; + +public class HaversineScorer implements Scorer { + @Override + public double computeCost(Station from, Station to) { + double R = 6372.8; // In kilometers + + double dLat = Math.toRadians(to.getLatitude() - from.getLatitude()); + double dLon = Math.toRadians(to.getLongitude() - from.getLongitude()); + double lat1 = Math.toRadians(from.getLatitude()); + double lat2 = Math.toRadians(to.getLatitude()); + + double a = Math.pow(Math.sin(dLat / 2),2) + Math.pow(Math.sin(dLon / 2),2) * Math.cos(lat1) * Math.cos(lat2); + double c = 2 * Math.asin(Math.sqrt(a)); + return R * c; + } +} diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/RouteFinderIntegrationTest.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/RouteFinderIntegrationTest.java new file mode 100644 index 0000000000..1e4ad56d94 --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/RouteFinderIntegrationTest.java @@ -0,0 +1,643 @@ +package com.baeldung.algorithms.astar.underground; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.baeldung.algorithms.astar.Graph; +import com.baeldung.algorithms.astar.RouteFinder; +import org.junit.Before; +import org.junit.Test; + +public class RouteFinderIntegrationTest { + + private Graph underground; + + private RouteFinder routeFinder; + + @Before + public void setUp() throws Exception { + Set stations = new HashSet<>(); + Map> connections = new HashMap<>(); + + stations.add(new Station("1", "Acton Town", 51.5028, -0.2801)); + stations.add(new Station("2", "Aldgate", 51.5143, -0.0755)); + stations.add(new Station("3", "Aldgate East", 51.5154, -0.0726)); + stations.add(new Station("4", "All Saints", 51.5107, -0.013)); + stations.add(new Station("5", "Alperton", 51.5407, -0.2997)); + stations.add(new Station("6", "Amersham", 51.6736, -0.607)); + stations.add(new Station("7", "Angel", 51.5322, -0.1058)); + stations.add(new Station("8", "Archway", 51.5653, -0.1353)); + stations.add(new Station("9", "Arnos Grove", 51.6164, -0.1331)); + stations.add(new Station("10", "Arsenal", 51.5586, -0.1059)); + stations.add(new Station("11", "Baker Street", 51.5226, -0.1571)); + stations.add(new Station("12", "Balham", 51.4431, -0.1525)); + stations.add(new Station("13", "Bank", 51.5133, -0.0886)); + stations.add(new Station("14", "Barbican", 51.5204, -0.0979)); + stations.add(new Station("15", "Barking", 51.5396, 0.081)); + stations.add(new Station("16", "Barkingside", 51.5856, 0.0887)); + stations.add(new Station("17", "Barons Court", 51.4905, -0.2139)); + stations.add(new Station("18", "Bayswater", 51.5121, -0.1879)); + stations.add(new Station("19", "Beckton", 51.5148, 0.0613)); + stations.add(new Station("20", "Beckton Park", 51.5087, 0.055)); + stations.add(new Station("21", "Becontree", 51.5403, 0.127)); + stations.add(new Station("22", "Belsize Park", 51.5504, -0.1642)); + stations.add(new Station("23", "Bermondsey", 51.4979, -0.0637)); + stations.add(new Station("24", "Bethnal Green", 51.527, -0.0549)); + stations.add(new Station("25", "Blackfriars", 51.512, -0.1031)); + stations.add(new Station("26", "Blackhorse Road", 51.5867, -0.0417)); + stations.add(new Station("27", "Blackwall", 51.5079, -0.0066)); + stations.add(new Station("28", "Bond Street", 51.5142, -0.1494)); + stations.add(new Station("29", "Borough", 51.5011, -0.0943)); + stations.add(new Station("30", "Boston Manor", 51.4956, -0.325)); + stations.add(new Station("31", "Bounds Green", 51.6071, -0.1243)); + stations.add(new Station("32", "Bow Church", 51.5273, -0.0208)); + stations.add(new Station("33", "Bow Road", 51.5269, -0.0247)); + stations.add(new Station("34", "Brent Cross", 51.5766, -0.2136)); + stations.add(new Station("35", "Brixton", 51.4627, -0.1145)); + stations.add(new Station("36", "Bromley-By-Bow", 51.5248, -0.0119)); + stations.add(new Station("37", "Buckhurst Hill", 51.6266, 0.0471)); + stations.add(new Station("38", "Burnt Oak", 51.6028, -0.2641)); + stations.add(new Station("39", "Caledonian Road", 51.5481, -0.1188)); + stations.add(new Station("40", "Camden Town", 51.5392, -0.1426)); + stations.add(new Station("41", "Canada Water", 51.4982, -0.0502)); + stations.add(new Station("42", "Canary Wharf", 51.5051, -0.0209)); + stations.add(new Station("43", "Canning Town", 51.5147, 0.0082)); + stations.add(new Station("44", "Cannon Street", 51.5113, -0.0904)); + stations.add(new Station("45", "Canons Park", 51.6078, -0.2947)); + stations.add(new Station("46", "Chalfont & Latimer", 51.6679, -0.561)); + stations.add(new Station("47", "Chalk Farm", 51.5441, -0.1538)); + stations.add(new Station("48", "Chancery Lane", 51.5185, -0.1111)); + stations.add(new Station("49", "Charing Cross", 51.508, -0.1247)); + stations.add(new Station("50", "Chesham", 51.7052, -0.611)); + stations.add(new Station("51", "Chigwell", 51.6177, 0.0755)); + stations.add(new Station("52", "Chiswick Park", 51.4946, -0.2678)); + stations.add(new Station("53", "Chorleywood", 51.6543, -0.5183)); + stations.add(new Station("54", "Clapham Common", 51.4618, -0.1384)); + stations.add(new Station("55", "Clapham North", 51.4649, -0.1299)); + stations.add(new Station("56", "Clapham South", 51.4527, -0.148)); + stations.add(new Station("57", "Cockfosters", 51.6517, -0.1496)); + stations.add(new Station("58", "Colindale", 51.5955, -0.2502)); + stations.add(new Station("59", "Colliers Wood", 51.418, -0.1778)); + stations.add(new Station("60", "Covent Garden", 51.5129, -0.1243)); + stations.add(new Station("61", "Crossharbour & London Arena", 51.4957, -0.0144)); + stations.add(new Station("62", "Croxley", 51.647, -0.4412)); + stations.add(new Station("63", "Custom House", 51.5095, 0.0276)); + stations.add(new Station("64", "Cutty Sark", 51.4827, -0.0096)); + stations.add(new Station("65", "Cyprus", 51.5085, 0.064)); + stations.add(new Station("66", "Dagenham East", 51.5443, 0.1655)); + stations.add(new Station("67", "Dagenham Heathway", 51.5417, 0.1469)); + stations.add(new Station("68", "Debden", 51.6455, 0.0838)); + stations.add(new Station("69", "Deptford Bridge", 51.474, -0.0216)); + stations.add(new Station("70", "Devons Road", 51.5223, -0.0173)); + stations.add(new Station("71", "Dollis Hill", 51.552, -0.2387)); + stations.add(new Station("72", "Ealing Broadway", 51.5152, -0.3017)); + stations.add(new Station("73", "Ealing Common", 51.5101, -0.2882)); + stations.add(new Station("74", "Earl's Court", 51.492, -0.1973)); + stations.add(new Station("75", "Eastcote", 51.5765, -0.397)); + stations.add(new Station("76", "East Acton", 51.5168, -0.2474)); + stations.add(new Station("77", "East Finchley", 51.5874, -0.165)); + stations.add(new Station("78", "East Ham", 51.5394, 0.0518)); + stations.add(new Station("79", "East India", 51.5093, -0.0021)); + stations.add(new Station("80", "East Putney", 51.4586, -0.2112)); + stations.add(new Station("81", "Edgware", 51.6137, -0.275)); + stations.add(new Station("82", "Edgware Road (B)", 51.5199, -0.1679)); + stations.add(new Station("83", "Edgware Road (C)", 51.5203, -0.17)); + stations.add(new Station("84", "Elephant & Castle", 51.4943, -0.1001)); + stations.add(new Station("85", "Elm Park", 51.5496, 0.1977)); + stations.add(new Station("86", "Elverson Road", 51.4693, -0.0174)); + stations.add(new Station("87", "Embankment", 51.5074, -0.1223)); + stations.add(new Station("88", "Epping", 51.6937, 0.1139)); + stations.add(new Station("89", "Euston", 51.5282, -0.1337)); + stations.add(new Station("90", "Euston Square", 51.526, -0.1359)); + stations.add(new Station("91", "Fairlop", 51.596, 0.0912)); + stations.add(new Station("92", "Farringdon", 51.5203, -0.1053)); + stations.add(new Station("93", "Finchley Central", 51.6012, -0.1932)); + stations.add(new Station("94", "Finchley Road", 51.5472, -0.1803)); + stations.add(new Station("95", "Finsbury Park", 51.5642, -0.1065)); + stations.add(new Station("96", "Fulham Broadway", 51.4804, -0.195)); + stations.add(new Station("97", "Gallions Reach", 51.5096, 0.0716)); + stations.add(new Station("98", "Gants Hill", 51.5765, 0.0663)); + stations.add(new Station("99", "Gloucester Road", 51.4945, -0.1829)); + stations.add(new Station("100", "Golders Green", 51.5724, -0.1941)); + stations.add(new Station("101", "Goldhawk Road", 51.5018, -0.2267)); + stations.add(new Station("102", "Goodge Street", 51.5205, -0.1347)); + stations.add(new Station("103", "Grange Hill", 51.6132, 0.0923)); + stations.add(new Station("104", "Great Portland Street", 51.5238, -0.1439)); + stations.add(new Station("105", "Greenford", 51.5423, -0.3456)); + stations.add(new Station("106", "Greenwich", 51.4781, -0.0149)); + stations.add(new Station("107", "Green Park", 51.5067, -0.1428)); + stations.add(new Station("108", "Gunnersbury", 51.4915, -0.2754)); + stations.add(new Station("109", "Hainault", 51.603, 0.0933)); + stations.add(new Station("110", "Hammersmith", 51.4936, -0.2251)); + stations.add(new Station("111", "Hampstead", 51.5568, -0.178)); + stations.add(new Station("112", "Hanger Lane", 51.5302, -0.2933)); + stations.add(new Station("113", "Harlesden", 51.5362, -0.2575)); + stations.add(new Station("114", "Harrow & Wealdston", 51.5925, -0.3351)); + stations.add(new Station("115", "Harrow-on-the-Hill", 51.5793, -0.3366)); + stations.add(new Station("116", "Hatton Cross", 51.4669, -0.4227)); + stations.add(new Station("117", "Heathrow Terminals 1, 2 & 3", 51.4713, -0.4524)); + stations.add(new Station("118", "Heathrow Terminal 4", 51.4598, -0.4476)); + stations.add(new Station("119", "Hendon Central", 51.5829, -0.2259)); + stations.add(new Station("120", "Heron Quays", 51.5033, -0.0215)); + stations.add(new Station("121", "High Barnet", 51.6503, -0.1943)); + stations.add(new Station("122", "High Street Kensington", 51.5009, -0.1925)); + stations.add(new Station("123", "Highbury & Islington", 51.546, -0.104)); + stations.add(new Station("124", "Highgate", 51.5777, -0.1458)); + stations.add(new Station("125", "Hillingdon", 51.5538, -0.4499)); + stations.add(new Station("126", "Holborn", 51.5174, -0.12)); + stations.add(new Station("127", "Holland Park", 51.5075, -0.206)); + stations.add(new Station("128", "Holloway Road", 51.5526, -0.1132)); + stations.add(new Station("129", "Hornchurch", 51.5539, 0.2184)); + stations.add(new Station("130", "Hounslow Central", 51.4713, -0.3665)); + stations.add(new Station("131", "Hounslow East", 51.4733, -0.3564)); + stations.add(new Station("132", "Hounslow West", 51.4734, -0.3855)); + stations.add(new Station("133", "Hyde Park Corner", 51.5027, -0.1527)); + stations.add(new Station("134", "Ickenham", 51.5619, -0.4421)); + stations.add(new Station("135", "Island Gardens", 51.4871, -0.0101)); + stations.add(new Station("136", "Kennington", 51.4884, -0.1053)); + stations.add(new Station("137", "Kensal Green", 51.5304, -0.225)); + stations.add(new Station("138", "Kensington (Olympia)", 51.4983, -0.2106)); + stations.add(new Station("139", "Kentish Town", 51.5507, -0.1402)); + stations.add(new Station("140", "Kenton", 51.5816, -0.3162)); + stations.add(new Station("141", "Kew Gardens", 51.477, -0.285)); + stations.add(new Station("142", "Kilburn", 51.5471, -0.2047)); + stations.add(new Station("143", "Kilburn Park", 51.5351, -0.1939)); + stations.add(new Station("144", "Kingsbury", 51.5846, -0.2786)); + stations.add(new Station("145", "King's Cross St. Pancras", 51.5308, -0.1238)); + stations.add(new Station("146", "Knightsbridge", 51.5015, -0.1607)); + stations.add(new Station("147", "Ladbroke Grove", 51.5172, -0.2107)); + stations.add(new Station("148", "Lambeth North", 51.4991, -0.1115)); + stations.add(new Station("149", "Lancaster Gate", 51.5119, -0.1756)); + stations.add(new Station("150", "Latimer Road", 51.5139, -0.2172)); + stations.add(new Station("151", "Leicester Square", 51.5113, -0.1281)); + stations.add(new Station("152", "Lewisham", 51.4657, -0.0142)); + stations.add(new Station("153", "Leyton", 51.5566, -0.0053)); + stations.add(new Station("154", "Leytonstone", 51.5683, 0.0083)); + stations.add(new Station("155", "Limehouse", 51.5123, -0.0396)); + stations.add(new Station("156", "Liverpool Street", 51.5178, -0.0823)); + stations.add(new Station("157", "London Bridge", 51.5052, -0.0864)); + stations.add(new Station("158", "Loughton", 51.6412, 0.0558)); + stations.add(new Station("159", "Maida Vale", 51.53, -0.1854)); + stations.add(new Station("160", "Manor House", 51.5712, -0.0958)); + stations.add(new Station("161", "Mansion House", 51.5122, -0.094)); + stations.add(new Station("162", "Marble Arch", 51.5136, -0.1586)); + stations.add(new Station("163", "Marylebone", 51.5225, -0.1631)); + stations.add(new Station("164", "Mile End", 51.5249, -0.0332)); + stations.add(new Station("165", "Mill Hill East", 51.6082, -0.2103)); + stations.add(new Station("166", "Monument", 51.5108, -0.0863)); + stations.add(new Station("167", "Moorgate", 51.5186, -0.0886)); + stations.add(new Station("168", "Moor Park", 51.6294, -0.432)); + stations.add(new Station("169", "Morden", 51.4022, -0.1948)); + stations.add(new Station("170", "Mornington Crescent", 51.5342, -0.1387)); + stations.add(new Station("171", "Mudchute", 51.4902, -0.0145)); + stations.add(new Station("172", "Neasden", 51.5542, -0.2503)); + stations.add(new Station("173", "Newbury Park", 51.5756, 0.0899)); + stations.add(new Station("174", "New Cross", 51.4767, -0.0327)); + stations.add(new Station("175", "New Cross Gate", 51.4757, -0.0402)); + stations.add(new Station("176", "Northfields", 51.4995, -0.3142)); + stations.add(new Station("177", "Northolt", 51.5483, -0.3687)); + stations.add(new Station("178", "Northwick Park", 51.5784, -0.3184)); + stations.add(new Station("179", "Northwood", 51.6111, -0.424)); + stations.add(new Station("180", "Northwood Hills", 51.6004, -0.4092)); + stations.add(new Station("181", "North Acton", 51.5237, -0.2597)); + stations.add(new Station("182", "North Ealing", 51.5175, -0.2887)); + stations.add(new Station("183", "North Greenwich", 51.5005, 0.0039)); + stations.add(new Station("184", "North Harrow", 51.5846, -0.3626)); + stations.add(new Station("185", "North Wembley", 51.5621, -0.3034)); + stations.add(new Station("186", "Notting Hill Gate", 51.5094, -0.1967)); + stations.add(new Station("187", "Oakwood", 51.6476, -0.1318)); + stations.add(new Station("188", "Old Street", 51.5263, -0.0873)); + stations.add(new Station("189", "Osterley", 51.4813, -0.3522)); + stations.add(new Station("190", "Oval", 51.4819, -0.113)); + stations.add(new Station("191", "Oxford Circus", 51.515, -0.1415)); + stations.add(new Station("192", "Paddington", 51.5154, -0.1755)); + stations.add(new Station("193", "Park Royal", 51.527, -0.2841)); + stations.add(new Station("194", "Parsons Green", 51.4753, -0.2011)); + stations.add(new Station("195", "Perivale", 51.5366, -0.3232)); + stations.add(new Station("196", "Picadilly Circus", 51.5098, -0.1342)); + stations.add(new Station("197", "Pimlico", 51.4893, -0.1334)); + stations.add(new Station("198", "Pinner", 51.5926, -0.3805)); + stations.add(new Station("199", "Plaistow", 51.5313, 0.0172)); + stations.add(new Station("200", "Poplar", 51.5077, -0.0173)); + stations.add(new Station("201", "Preston Road", 51.572, -0.2954)); + stations.add(new Station("202", "Prince Regent", 51.5093, 0.0336)); + stations.add(new Station("203", "Pudding Mill Lane", 51.5343, -0.0139)); + stations.add(new Station("204", "Putney Bridge", 51.4682, -0.2089)); + stations.add(new Station("205", "Queen's Park", 51.5341, -0.2047)); + stations.add(new Station("206", "Queensbury", 51.5942, -0.2861)); + stations.add(new Station("207", "Queensway", 51.5107, -0.1877)); + stations.add(new Station("208", "Ravenscourt Park", 51.4942, -0.2359)); + stations.add(new Station("209", "Rayners Lane", 51.5753, -0.3714)); + stations.add(new Station("210", "Redbridge", 51.5763, 0.0454)); + stations.add(new Station("211", "Regent's Park", 51.5234, -0.1466)); + stations.add(new Station("212", "Richmond", 51.4633, -0.3013)); + stations.add(new Station("213", "Rickmansworth", 51.6404, -0.4733)); + stations.add(new Station("214", "Roding Valley", 51.6171, 0.0439)); + stations.add(new Station("215", "Rotherhithe", 51.501, -0.0525)); + stations.add(new Station("216", "Royal Albert", 51.5084, 0.0465)); + stations.add(new Station("217", "Royal Oak", 51.519, -0.188)); + stations.add(new Station("218", "Royal Victoria", 51.5091, 0.0181)); + stations.add(new Station("219", "Ruislip", 51.5715, -0.4213)); + stations.add(new Station("220", "Ruislip Gardens", 51.5606, -0.4103)); + stations.add(new Station("221", "Ruislip Manor", 51.5732, -0.4125)); + stations.add(new Station("222", "Russell Square", 51.523, -0.1244)); + stations.add(new Station("223", "Seven Sisters", 51.5822, -0.0749)); + stations.add(new Station("224", "Shadwell", 51.5117, -0.056)); + stations.add(new Station("225", "Shepherd's Bush (C)", 51.5046, -0.2187)); + stations.add(new Station("226", "Shepherd's Bush (H)", 51.5058, -0.2265)); + stations.add(new Station("227", "Shoreditch", 51.5227, -0.0708)); + stations.add(new Station("228", "Sloane Square", 51.4924, -0.1565)); + stations.add(new Station("229", "Snaresbrook", 51.5808, 0.0216)); + stations.add(new Station("230", "Southfields", 51.4454, -0.2066)); + stations.add(new Station("231", "Southgate", 51.6322, -0.128)); + stations.add(new Station("232", "Southwark", 51.501, -0.1052)); + stations.add(new Station("233", "South Ealing", 51.5011, -0.3072)); + stations.add(new Station("234", "South Harrow", 51.5646, -0.3521)); + stations.add(new Station("235", "South Kensington", 51.4941, -0.1738)); + stations.add(new Station("236", "South Kenton", 51.5701, -0.3081)); + stations.add(new Station("237", "South Quay", 51.5007, -0.0191)); + stations.add(new Station("238", "South Ruislip", 51.5569, -0.3988)); + stations.add(new Station("239", "South Wimbledon", 51.4154, -0.1919)); + stations.add(new Station("240", "South Woodford", 51.5917, 0.0275)); + stations.add(new Station("241", "Stamford Brook", 51.495, -0.2459)); + stations.add(new Station("242", "Stanmore", 51.6194, -0.3028)); + stations.add(new Station("243", "Stepney Green", 51.5221, -0.047)); + stations.add(new Station("244", "Stockwell", 51.4723, -0.123)); + stations.add(new Station("245", "Stonebridge Park", 51.5439, -0.2759)); + stations.add(new Station("246", "Stratford", 51.5416, -0.0042)); + stations.add(new Station("247", "St. James's Park", 51.4994, -0.1335)); + stations.add(new Station("248", "St. John's Wood", 51.5347, -0.174)); + stations.add(new Station("249", "St. Paul's", 51.5146, -0.0973)); + stations.add(new Station("250", "Sudbury Hill", 51.5569, -0.3366)); + stations.add(new Station("251", "Sudbury Town", 51.5507, -0.3156)); + stations.add(new Station("252", "Surrey Quays", 51.4933, -0.0478)); + stations.add(new Station("253", "Swiss Cottage", 51.5432, -0.1738)); + stations.add(new Station("254", "Temple", 51.5111, -0.1141)); + stations.add(new Station("255", "Theydon Bois", 51.6717, 0.1033)); + stations.add(new Station("256", "Tooting Bec", 51.4361, -0.1598)); + stations.add(new Station("257", "Tooting Broadway", 51.4275, -0.168)); + stations.add(new Station("258", "Tottenham Court Road", 51.5165, -0.131)); + stations.add(new Station("259", "Tottenham Hale", 51.5882, -0.0594)); + stations.add(new Station("260", "Totteridge & Whetstone", 51.6302, -0.1791)); + stations.add(new Station("261", "Tower Gateway", 51.5106, -0.0743)); + stations.add(new Station("262", "Tower Hill", 51.5098, -0.0766)); + stations.add(new Station("263", "Tufnell Park", 51.5567, -0.1374)); + stations.add(new Station("264", "Turnham Green", 51.4951, -0.2547)); + stations.add(new Station("265", "Turnpike Lane", 51.5904, -0.1028)); + stations.add(new Station("266", "Upminster", 51.559, 0.251)); + stations.add(new Station("267", "Upminster Bridge", 51.5582, 0.2343)); + stations.add(new Station("268", "Upney", 51.5385, 0.1014)); + stations.add(new Station("269", "Upton Park", 51.5352, 0.0343)); + stations.add(new Station("270", "Uxbridge", 51.5463, -0.4786)); + stations.add(new Station("271", "Vauxhall", 51.4861, -0.1253)); + stations.add(new Station("272", "Victoria", 51.4965, -0.1447)); + stations.add(new Station("273", "Walthamstow Central", 51.583, -0.0195)); + stations.add(new Station("274", "Wanstead", 51.5775, 0.0288)); + stations.add(new Station("275", "Wapping", 51.5043, -0.0558)); + stations.add(new Station("276", "Warren Street", 51.5247, -0.1384)); + stations.add(new Station("277", "Warwick Avenue", 51.5235, -0.1835)); + stations.add(new Station("278", "Waterloo", 51.5036, -0.1143)); + stations.add(new Station("279", "Watford", 51.6573, -0.4177)); + stations.add(new Station("280", "Wembley Central", 51.5519, -0.2963)); + stations.add(new Station("281", "Wembley Park", 51.5635, -0.2795)); + stations.add(new Station("282", "Westbourne Park", 51.521, -0.2011)); + stations.add(new Station("283", "Westferry", 51.5097, -0.0265)); + stations.add(new Station("284", "Westminster", 51.501, -0.1254)); + stations.add(new Station("285", "West Acton", 51.518, -0.2809)); + stations.add(new Station("286", "West Brompton", 51.4872, -0.1953)); + stations.add(new Station("287", "West Finchley", 51.6095, -0.1883)); + stations.add(new Station("288", "West Ham", 51.5287, 0.0056)); + stations.add(new Station("289", "West Hampstead", 51.5469, -0.1906)); + stations.add(new Station("290", "West Harrow", 51.5795, -0.3533)); + stations.add(new Station("291", "West India Quay", 51.507, -0.0203)); + stations.add(new Station("292", "West Kensington", 51.4907, -0.2065)); + stations.add(new Station("293", "West Ruislip", 51.5696, -0.4376)); + stations.add(new Station("294", "Whitechapel", 51.5194, -0.0612)); + stations.add(new Station("295", "White City", 51.512, -0.2239)); + stations.add(new Station("296", "Willesden Green", 51.5492, -0.2215)); + stations.add(new Station("297", "Willesden Junction", 51.5326, -0.2478)); + stations.add(new Station("298", "Wimbledon", 51.4214, -0.2064)); + stations.add(new Station("299", "Wimbledon Park", 51.4343, -0.1992)); + stations.add(new Station("300", "Woodford", 51.607, 0.0341)); + stations.add(new Station("301", "Woodside Park", 51.6179, -0.1856)); + stations.add(new Station("302", "Wood Green", 51.5975, -0.1097)); + + connections.put("1", Stream.of("52","73","73","233","264").collect(Collectors.toSet())); + connections.put("2", Stream.of("156","262","156").collect(Collectors.toSet())); + connections.put("3", Stream.of("262","294","156","294").collect(Collectors.toSet())); + connections.put("4", Stream.of("70","200").collect(Collectors.toSet())); + connections.put("5", Stream.of("193","251").collect(Collectors.toSet())); + connections.put("6", Stream.of("46").collect(Collectors.toSet())); + connections.put("7", Stream.of("145","188").collect(Collectors.toSet())); + connections.put("8", Stream.of("124","263").collect(Collectors.toSet())); + connections.put("9", Stream.of("31","231").collect(Collectors.toSet())); + connections.put("10", Stream.of("95","128").collect(Collectors.toSet())); + connections.put("11", Stream.of("163","211","83","104","83","104","28","248","94","104").collect(Collectors.toSet())); + connections.put("12", Stream.of("56","256").collect(Collectors.toSet())); + connections.put("13", Stream.of("156","249","224","157","167","278").collect(Collectors.toSet())); + connections.put("14", Stream.of("92","167","92","167","92","167").collect(Collectors.toSet())); + connections.put("15", Stream.of("78","268","78").collect(Collectors.toSet())); + connections.put("16", Stream.of("91","173").collect(Collectors.toSet())); + connections.put("17", Stream.of("110","292","74","110").collect(Collectors.toSet())); + connections.put("18", Stream.of("186","192","186","192").collect(Collectors.toSet())); + connections.put("19", Stream.of("97").collect(Collectors.toSet())); + connections.put("20", Stream.of("65","216").collect(Collectors.toSet())); + connections.put("21", Stream.of("67","268").collect(Collectors.toSet())); + connections.put("22", Stream.of("47","111").collect(Collectors.toSet())); + connections.put("23", Stream.of("41","157").collect(Collectors.toSet())); + connections.put("24", Stream.of("156","164").collect(Collectors.toSet())); + connections.put("25", Stream.of("161","254","161","254").collect(Collectors.toSet())); + connections.put("26", Stream.of("259","273").collect(Collectors.toSet())); + connections.put("27", Stream.of("79","200").collect(Collectors.toSet())); + connections.put("28", Stream.of("162","191","11","107").collect(Collectors.toSet())); + connections.put("29", Stream.of("84","157").collect(Collectors.toSet())); + connections.put("30", Stream.of("176","189").collect(Collectors.toSet())); + connections.put("31", Stream.of("9","302").collect(Collectors.toSet())); + connections.put("32", Stream.of("70","203").collect(Collectors.toSet())); + connections.put("33", Stream.of("36","164","36","164").collect(Collectors.toSet())); + connections.put("34", Stream.of("100","119").collect(Collectors.toSet())); + connections.put("35", Stream.of("244").collect(Collectors.toSet())); + connections.put("36", Stream.of("33","288","33","288").collect(Collectors.toSet())); + connections.put("37", Stream.of("158","300").collect(Collectors.toSet())); + connections.put("38", Stream.of("58","81").collect(Collectors.toSet())); + connections.put("39", Stream.of("128","145").collect(Collectors.toSet())); + connections.put("40", Stream.of("47","89","139","170").collect(Collectors.toSet())); + connections.put("41", Stream.of("215","252","23","42").collect(Collectors.toSet())); + connections.put("42", Stream.of("120","291","41","183").collect(Collectors.toSet())); + connections.put("43", Stream.of("79","218","183","288").collect(Collectors.toSet())); + connections.put("44", Stream.of("161","166","161","166").collect(Collectors.toSet())); + connections.put("45", Stream.of("206","242").collect(Collectors.toSet())); + connections.put("46", Stream.of("6","50","53").collect(Collectors.toSet())); + connections.put("47", Stream.of("22","40").collect(Collectors.toSet())); + connections.put("48", Stream.of("126","249").collect(Collectors.toSet())); + connections.put("49", Stream.of("87","196","87","151").collect(Collectors.toSet())); + connections.put("50", Stream.of("46").collect(Collectors.toSet())); + connections.put("51", Stream.of("103","214").collect(Collectors.toSet())); + connections.put("52", Stream.of("1","264").collect(Collectors.toSet())); + connections.put("53", Stream.of("46","213").collect(Collectors.toSet())); + connections.put("54", Stream.of("55","56").collect(Collectors.toSet())); + connections.put("55", Stream.of("54","244").collect(Collectors.toSet())); + connections.put("56", Stream.of("12","54").collect(Collectors.toSet())); + connections.put("57", Stream.of("187").collect(Collectors.toSet())); + connections.put("58", Stream.of("38","119").collect(Collectors.toSet())); + connections.put("59", Stream.of("239","257").collect(Collectors.toSet())); + connections.put("60", Stream.of("126","151").collect(Collectors.toSet())); + connections.put("61", Stream.of("171","237").collect(Collectors.toSet())); + connections.put("62", Stream.of("168","279").collect(Collectors.toSet())); + connections.put("63", Stream.of("202","218").collect(Collectors.toSet())); + connections.put("64", Stream.of("106","135").collect(Collectors.toSet())); + connections.put("65", Stream.of("20","97").collect(Collectors.toSet())); + connections.put("66", Stream.of("67","85").collect(Collectors.toSet())); + connections.put("67", Stream.of("21","66").collect(Collectors.toSet())); + connections.put("68", Stream.of("158","255").collect(Collectors.toSet())); + connections.put("69", Stream.of("86","106").collect(Collectors.toSet())); + connections.put("70", Stream.of("4","32").collect(Collectors.toSet())); + connections.put("71", Stream.of("172","296").collect(Collectors.toSet())); + connections.put("72", Stream.of("285","73").collect(Collectors.toSet())); + connections.put("73", Stream.of("72","1","1","182").collect(Collectors.toSet())); + connections.put("74", Stream.of("99","122","138","286","292","17","99").collect(Collectors.toSet())); + connections.put("75", Stream.of("209","221","209","221").collect(Collectors.toSet())); + connections.put("76", Stream.of("181","295").collect(Collectors.toSet())); + connections.put("77", Stream.of("93","124").collect(Collectors.toSet())); + connections.put("78", Stream.of("15","269","15","269").collect(Collectors.toSet())); + connections.put("79", Stream.of("27","43").collect(Collectors.toSet())); + connections.put("80", Stream.of("204","230").collect(Collectors.toSet())); + connections.put("81", Stream.of("38").collect(Collectors.toSet())); + connections.put("82", Stream.of("163","192").collect(Collectors.toSet())); + connections.put("83", Stream.of("11","192","192","11","192").collect(Collectors.toSet())); + connections.put("84", Stream.of("148","29","136").collect(Collectors.toSet())); + connections.put("85", Stream.of("66","129").collect(Collectors.toSet())); + connections.put("86", Stream.of("69","152").collect(Collectors.toSet())); + connections.put("87", Stream.of("49","278","254","284","254","284","49","278").collect(Collectors.toSet())); + connections.put("88", Stream.of("255").collect(Collectors.toSet())); + connections.put("89", Stream.of("40","145","170","276","145","276").collect(Collectors.toSet())); + connections.put("90", Stream.of("104","145","104","145","104","145").collect(Collectors.toSet())); + connections.put("91", Stream.of("16","109").collect(Collectors.toSet())); + connections.put("92", Stream.of("14","145","14","145","14","145").collect(Collectors.toSet())); + connections.put("93", Stream.of("77","165","287").collect(Collectors.toSet())); + connections.put("94", Stream.of("253","289","11","281").collect(Collectors.toSet())); + connections.put("95", Stream.of("10","160","123","223").collect(Collectors.toSet())); + connections.put("96", Stream.of("194","286").collect(Collectors.toSet())); + connections.put("97", Stream.of("19","65").collect(Collectors.toSet())); + connections.put("98", Stream.of("173","210").collect(Collectors.toSet())); + connections.put("99", Stream.of("122","235","74","235","74","235").collect(Collectors.toSet())); + connections.put("100", Stream.of("34","111").collect(Collectors.toSet())); + connections.put("101", Stream.of("110","226").collect(Collectors.toSet())); + connections.put("102", Stream.of("258","276").collect(Collectors.toSet())); + connections.put("103", Stream.of("51","109").collect(Collectors.toSet())); + connections.put("104", Stream.of("11","90","11","90","11","90").collect(Collectors.toSet())); + connections.put("105", Stream.of("177","195").collect(Collectors.toSet())); + connections.put("106", Stream.of("64","69").collect(Collectors.toSet())); + connections.put("107", Stream.of("28","284","133","196","191","272").collect(Collectors.toSet())); + connections.put("108", Stream.of("141","264").collect(Collectors.toSet())); + connections.put("109", Stream.of("91","103").collect(Collectors.toSet())); + connections.put("110", Stream.of("17","208","101","17","264").collect(Collectors.toSet())); + connections.put("111", Stream.of("22","100").collect(Collectors.toSet())); + connections.put("112", Stream.of("181","195").collect(Collectors.toSet())); + connections.put("113", Stream.of("245","297").collect(Collectors.toSet())); + connections.put("114", Stream.of("140").collect(Collectors.toSet())); + connections.put("115", Stream.of("178","184","290").collect(Collectors.toSet())); + connections.put("116", Stream.of("117","118","132").collect(Collectors.toSet())); + connections.put("117", Stream.of("116","118").collect(Collectors.toSet())); + connections.put("118", Stream.of("116","117").collect(Collectors.toSet())); + connections.put("119", Stream.of("34","58").collect(Collectors.toSet())); + connections.put("120", Stream.of("42","237").collect(Collectors.toSet())); + connections.put("121", Stream.of("260").collect(Collectors.toSet())); + connections.put("122", Stream.of("99","186","74","186").collect(Collectors.toSet())); + connections.put("123", Stream.of("95","145").collect(Collectors.toSet())); + connections.put("124", Stream.of("8","77").collect(Collectors.toSet())); + connections.put("125", Stream.of("134","270","134","270").collect(Collectors.toSet())); + connections.put("126", Stream.of("48","258","60","222").collect(Collectors.toSet())); + connections.put("127", Stream.of("186","225").collect(Collectors.toSet())); + connections.put("128", Stream.of("10","39").collect(Collectors.toSet())); + connections.put("129", Stream.of("85","267").collect(Collectors.toSet())); + connections.put("130", Stream.of("131","132").collect(Collectors.toSet())); + connections.put("131", Stream.of("130","189").collect(Collectors.toSet())); + connections.put("132", Stream.of("116","130").collect(Collectors.toSet())); + connections.put("133", Stream.of("107","146").collect(Collectors.toSet())); + connections.put("134", Stream.of("125","219","125","219").collect(Collectors.toSet())); + connections.put("135", Stream.of("64","171").collect(Collectors.toSet())); + connections.put("136", Stream.of("84","190","278").collect(Collectors.toSet())); + connections.put("137", Stream.of("205","297").collect(Collectors.toSet())); + connections.put("138", Stream.of("74").collect(Collectors.toSet())); + connections.put("139", Stream.of("40","263").collect(Collectors.toSet())); + connections.put("140", Stream.of("114","236").collect(Collectors.toSet())); + connections.put("141", Stream.of("108","212").collect(Collectors.toSet())); + connections.put("142", Stream.of("289","296").collect(Collectors.toSet())); + connections.put("143", Stream.of("159","205").collect(Collectors.toSet())); + connections.put("144", Stream.of("206","281").collect(Collectors.toSet())); + connections.put("145", Stream.of("90","92","90","92","90","92","7","89","39","222","89","123").collect(Collectors.toSet())); + connections.put("146", Stream.of("133","235").collect(Collectors.toSet())); + connections.put("147", Stream.of("150","282").collect(Collectors.toSet())); + connections.put("148", Stream.of("84","278").collect(Collectors.toSet())); + connections.put("149", Stream.of("162","207").collect(Collectors.toSet())); + connections.put("150", Stream.of("147","226").collect(Collectors.toSet())); + connections.put("151", Stream.of("49","258","60","196").collect(Collectors.toSet())); + connections.put("152", Stream.of("86").collect(Collectors.toSet())); + connections.put("153", Stream.of("154","246").collect(Collectors.toSet())); + connections.put("154", Stream.of("153","229","274").collect(Collectors.toSet())); + connections.put("155", Stream.of("224","283").collect(Collectors.toSet())); + connections.put("156", Stream.of("13","24","2","167","3","167","2","167").collect(Collectors.toSet())); + connections.put("157", Stream.of("23","232","13","29").collect(Collectors.toSet())); + connections.put("158", Stream.of("37","68").collect(Collectors.toSet())); + connections.put("159", Stream.of("143","277").collect(Collectors.toSet())); + connections.put("160", Stream.of("95","265").collect(Collectors.toSet())); + connections.put("161", Stream.of("25","44","25","44").collect(Collectors.toSet())); + connections.put("162", Stream.of("28","149").collect(Collectors.toSet())); + connections.put("163", Stream.of("11","82").collect(Collectors.toSet())); + connections.put("164", Stream.of("24","246","33","243","33","243").collect(Collectors.toSet())); + connections.put("165", Stream.of("93").collect(Collectors.toSet())); + connections.put("166", Stream.of("44","262","44","262").collect(Collectors.toSet())); + connections.put("167", Stream.of("14","156","14","156","14","156","13","188").collect(Collectors.toSet())); + connections.put("168", Stream.of("62","179","213").collect(Collectors.toSet())); + connections.put("169", Stream.of("239").collect(Collectors.toSet())); + connections.put("170", Stream.of("40","89").collect(Collectors.toSet())); + connections.put("171", Stream.of("61","135").collect(Collectors.toSet())); + connections.put("172", Stream.of("71","281").collect(Collectors.toSet())); + connections.put("173", Stream.of("16","98").collect(Collectors.toSet())); + connections.put("174", Stream.of("252").collect(Collectors.toSet())); + connections.put("175", Stream.of("252").collect(Collectors.toSet())); + connections.put("176", Stream.of("30","233").collect(Collectors.toSet())); + connections.put("177", Stream.of("105","238").collect(Collectors.toSet())); + connections.put("178", Stream.of("115","201").collect(Collectors.toSet())); + connections.put("179", Stream.of("168","180").collect(Collectors.toSet())); + connections.put("180", Stream.of("179","198").collect(Collectors.toSet())); + connections.put("181", Stream.of("76","112","285").collect(Collectors.toSet())); + connections.put("182", Stream.of("73","193").collect(Collectors.toSet())); + connections.put("183", Stream.of("42","43").collect(Collectors.toSet())); + connections.put("184", Stream.of("115","198").collect(Collectors.toSet())); + connections.put("185", Stream.of("236","280").collect(Collectors.toSet())); + connections.put("186", Stream.of("127","207","18","122","18","122").collect(Collectors.toSet())); + connections.put("187", Stream.of("57","231").collect(Collectors.toSet())); + connections.put("188", Stream.of("7","167").collect(Collectors.toSet())); + connections.put("189", Stream.of("30","131").collect(Collectors.toSet())); + connections.put("190", Stream.of("136","244").collect(Collectors.toSet())); + connections.put("191", Stream.of("196","211","28","258","107","276").collect(Collectors.toSet())); + connections.put("192", Stream.of("82","277","18","83","18","83","83","217").collect(Collectors.toSet())); + connections.put("193", Stream.of("5","182").collect(Collectors.toSet())); + connections.put("194", Stream.of("96","204").collect(Collectors.toSet())); + connections.put("195", Stream.of("105","112").collect(Collectors.toSet())); + connections.put("196", Stream.of("49","191","107","151").collect(Collectors.toSet())); + connections.put("197", Stream.of("271","272").collect(Collectors.toSet())); + connections.put("198", Stream.of("180","184").collect(Collectors.toSet())); + connections.put("199", Stream.of("269","288","269","288").collect(Collectors.toSet())); + connections.put("200", Stream.of("4","27","283","291").collect(Collectors.toSet())); + connections.put("201", Stream.of("178","281").collect(Collectors.toSet())); + connections.put("202", Stream.of("63","216").collect(Collectors.toSet())); + connections.put("203", Stream.of("32","246").collect(Collectors.toSet())); + connections.put("204", Stream.of("80","194").collect(Collectors.toSet())); + connections.put("205", Stream.of("137","143").collect(Collectors.toSet())); + connections.put("206", Stream.of("45","144").collect(Collectors.toSet())); + connections.put("207", Stream.of("149","186").collect(Collectors.toSet())); + connections.put("208", Stream.of("110","241").collect(Collectors.toSet())); + connections.put("209", Stream.of("75","290","75","234").collect(Collectors.toSet())); + connections.put("210", Stream.of("98","274").collect(Collectors.toSet())); + connections.put("211", Stream.of("11","191").collect(Collectors.toSet())); + connections.put("212", Stream.of("141").collect(Collectors.toSet())); + connections.put("213", Stream.of("53","168").collect(Collectors.toSet())); + connections.put("214", Stream.of("51","300").collect(Collectors.toSet())); + connections.put("215", Stream.of("41","275").collect(Collectors.toSet())); + connections.put("216", Stream.of("20","202").collect(Collectors.toSet())); + connections.put("217", Stream.of("192","282").collect(Collectors.toSet())); + connections.put("218", Stream.of("43","63").collect(Collectors.toSet())); + connections.put("219", Stream.of("134","221","134","221").collect(Collectors.toSet())); + connections.put("220", Stream.of("238","293").collect(Collectors.toSet())); + connections.put("221", Stream.of("75","219","75","219").collect(Collectors.toSet())); + connections.put("222", Stream.of("126","145").collect(Collectors.toSet())); + connections.put("223", Stream.of("95","259").collect(Collectors.toSet())); + connections.put("224", Stream.of("13","155","261","275","294").collect(Collectors.toSet())); + connections.put("225", Stream.of("127","295").collect(Collectors.toSet())); + connections.put("226", Stream.of("101","150").collect(Collectors.toSet())); + connections.put("227", Stream.of("294").collect(Collectors.toSet())); + connections.put("228", Stream.of("235","272","235","272").collect(Collectors.toSet())); + connections.put("229", Stream.of("154","240").collect(Collectors.toSet())); + connections.put("230", Stream.of("80","299").collect(Collectors.toSet())); + connections.put("231", Stream.of("9","187").collect(Collectors.toSet())); + connections.put("232", Stream.of("157","278").collect(Collectors.toSet())); + connections.put("233", Stream.of("1","176").collect(Collectors.toSet())); + connections.put("234", Stream.of("209","250").collect(Collectors.toSet())); + connections.put("235", Stream.of("99","228","99","228","99","146").collect(Collectors.toSet())); + connections.put("236", Stream.of("140","185").collect(Collectors.toSet())); + connections.put("237", Stream.of("61","120").collect(Collectors.toSet())); + connections.put("238", Stream.of("177","220").collect(Collectors.toSet())); + connections.put("239", Stream.of("59","169").collect(Collectors.toSet())); + connections.put("240", Stream.of("229","300").collect(Collectors.toSet())); + connections.put("241", Stream.of("208","264").collect(Collectors.toSet())); + connections.put("242", Stream.of("45").collect(Collectors.toSet())); + connections.put("243", Stream.of("164","294","164","294").collect(Collectors.toSet())); + connections.put("244", Stream.of("55","190","35","271").collect(Collectors.toSet())); + connections.put("245", Stream.of("113","280").collect(Collectors.toSet())); + connections.put("246", Stream.of("153","164","203","288").collect(Collectors.toSet())); + connections.put("247", Stream.of("272","284","272","284").collect(Collectors.toSet())); + connections.put("248", Stream.of("11","253").collect(Collectors.toSet())); + connections.put("249", Stream.of("13","48").collect(Collectors.toSet())); + connections.put("250", Stream.of("234","251").collect(Collectors.toSet())); + connections.put("251", Stream.of("5","250").collect(Collectors.toSet())); + connections.put("252", Stream.of("41","174","175").collect(Collectors.toSet())); + connections.put("253", Stream.of("94","248").collect(Collectors.toSet())); + connections.put("254", Stream.of("25","87","25","87").collect(Collectors.toSet())); + connections.put("255", Stream.of("68","88").collect(Collectors.toSet())); + connections.put("256", Stream.of("12","257").collect(Collectors.toSet())); + connections.put("257", Stream.of("59","256").collect(Collectors.toSet())); + connections.put("258", Stream.of("126","191","102","151").collect(Collectors.toSet())); + connections.put("259", Stream.of("26","223").collect(Collectors.toSet())); + connections.put("260", Stream.of("121","301").collect(Collectors.toSet())); + connections.put("261", Stream.of("224").collect(Collectors.toSet())); + connections.put("262", Stream.of("2","166","3","166").collect(Collectors.toSet())); + connections.put("263", Stream.of("8","139").collect(Collectors.toSet())); + connections.put("264", Stream.of("52","108","241","1","110").collect(Collectors.toSet())); + connections.put("265", Stream.of("160","302").collect(Collectors.toSet())); + connections.put("266", Stream.of("267").collect(Collectors.toSet())); + connections.put("267", Stream.of("129","266").collect(Collectors.toSet())); + connections.put("268", Stream.of("15","21").collect(Collectors.toSet())); + connections.put("269", Stream.of("78","199","78","199").collect(Collectors.toSet())); + connections.put("270", Stream.of("125","125").collect(Collectors.toSet())); + connections.put("271", Stream.of("197","244").collect(Collectors.toSet())); + connections.put("272", Stream.of("228","247","228","247","107","197").collect(Collectors.toSet())); + connections.put("273", Stream.of("26").collect(Collectors.toSet())); + connections.put("274", Stream.of("154","210").collect(Collectors.toSet())); + connections.put("275", Stream.of("215","224").collect(Collectors.toSet())); + connections.put("276", Stream.of("89","102","89","191").collect(Collectors.toSet())); + connections.put("277", Stream.of("159","192").collect(Collectors.toSet())); + connections.put("278", Stream.of("87","148","232","284","87","136","13").collect(Collectors.toSet())); + connections.put("279", Stream.of("62").collect(Collectors.toSet())); + connections.put("280", Stream.of("185","245").collect(Collectors.toSet())); + connections.put("281", Stream.of("144","172","94","201").collect(Collectors.toSet())); + connections.put("282", Stream.of("147","217").collect(Collectors.toSet())); + connections.put("283", Stream.of("155","200","291").collect(Collectors.toSet())); + connections.put("284", Stream.of("87","247","87","247","107","278").collect(Collectors.toSet())); + connections.put("285", Stream.of("72","181").collect(Collectors.toSet())); + connections.put("286", Stream.of("74","96").collect(Collectors.toSet())); + connections.put("287", Stream.of("93","301").collect(Collectors.toSet())); + connections.put("288", Stream.of("36","199","36","199","43","246").collect(Collectors.toSet())); + connections.put("289", Stream.of("94","142").collect(Collectors.toSet())); + connections.put("290", Stream.of("115","209").collect(Collectors.toSet())); + connections.put("291", Stream.of("42","200","283").collect(Collectors.toSet())); + connections.put("292", Stream.of("17","74").collect(Collectors.toSet())); + connections.put("293", Stream.of("220").collect(Collectors.toSet())); + connections.put("294", Stream.of("3","243","224","227","3","243").collect(Collectors.toSet())); + connections.put("295", Stream.of("76","225").collect(Collectors.toSet())); + connections.put("296", Stream.of("71","142").collect(Collectors.toSet())); + connections.put("297", Stream.of("113","137").collect(Collectors.toSet())); + connections.put("298", Stream.of("299").collect(Collectors.toSet())); + connections.put("299", Stream.of("230","298").collect(Collectors.toSet())); + connections.put("300", Stream.of("37","214","240").collect(Collectors.toSet())); + connections.put("301", Stream.of("260","287").collect(Collectors.toSet())); + connections.put("302", Stream.of("31","265").collect(Collectors.toSet())); + + underground = new Graph<>(stations, connections); + routeFinder = new RouteFinder<>(underground, new HaversineScorer(), new HaversineScorer()); + } + + @Test + public void findRoute() { + List route = routeFinder.findRoute(underground.getNode("74"), underground.getNode("7")); + + System.out.println(route.stream().map(Station::getName).collect(Collectors.toList())); + } +} diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/Station.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/Station.java new file mode 100644 index 0000000000..59bd8d62c2 --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/Station.java @@ -0,0 +1,42 @@ +package com.baeldung.algorithms.astar.underground; + +import java.util.StringJoiner; + +import com.baeldung.algorithms.astar.GraphNode; + +public class Station implements GraphNode { + private final String id; + private final String name; + private final double latitude; + private final double longitude; + + public Station(String id, String name, double latitude, double longitude) { + this.id = id; + this.name = name; + this.latitude = latitude; + this.longitude = longitude; + } + + @Override + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public double getLatitude() { + return latitude; + } + + public double getLongitude() { + return longitude; + } + + @Override + public String toString() { + return new StringJoiner(", ", Station.class.getSimpleName() + "[", "]").add("id='" + id + "'") + .add("name='" + name + "'").add("latitude=" + latitude).add("longitude=" + longitude).toString(); + } +} diff --git a/algorithms-miscellaneous-2/src/test/resources/graph.png b/algorithms-miscellaneous-2/src/test/resources/graph.png index 7165a51782..12af62c131 100644 Binary files a/algorithms-miscellaneous-2/src/test/resources/graph.png and b/algorithms-miscellaneous-2/src/test/resources/graph.png differ diff --git a/algorithms-miscellaneous-3/README.md b/algorithms-miscellaneous-3/README.md index 9748595a34..23a10258a3 100644 --- a/algorithms-miscellaneous-3/README.md +++ b/algorithms-miscellaneous-3/README.md @@ -14,4 +14,6 @@ This module contains articles about algorithms. Some classes of algorithms, e.g. - [A Guide to the Folding Technique in Java](https://www.baeldung.com/folding-hashing-technique) - [Creating a Triangle with for Loops in Java](https://www.baeldung.com/java-print-triangle) - [Efficient Word Frequency Calculator in Java](https://www.baeldung.com/java-word-frequency) -- More articles: [[<-- prev]](/algorithms-miscellaneous-2) [[next -->]](/algorithms-miscellaneous-4) \ No newline at end of file +- [The K-Means Clustering Algorithm in Java](https://www.baeldung.com/java-k-means-clustering-algorithm) +- [Creating a Custom Annotation in Java](https://www.baeldung.com/java-custom-annotation) +- More articles: [[<-- prev]](/algorithms-miscellaneous-2) [[next -->]](/algorithms-miscellaneous-4) diff --git a/algorithms-miscellaneous-4/README.md b/algorithms-miscellaneous-4/README.md index fabb4d29b8..fd33b58d72 100644 --- a/algorithms-miscellaneous-4/README.md +++ b/algorithms-miscellaneous-4/README.md @@ -1,9 +1,14 @@ -## Relevant articles: +## Algorithms - Miscellaneous + +This module contains articles about algorithms. Some classes of algorithms, e.g., [sorting](https://github.com/eugenp/tutorials/blob/algorithms-sorting) and [genetic algorithms](https://github.com/eugenp/tutorials/blob/algorithms-genetic), have their own dedicated modules. + +### Relevant articles: - [Multi-Swarm Optimization Algorithm in Java](https://www.baeldung.com/java-multi-swarm-algorithm) -- [String Search Algorithms for Large Texts](https://www.baeldung.com/java-full-text-search-algorithms) - [Check If a String Contains All The Letters of The Alphabet](https://www.baeldung.com/java-string-contains-all-letters) - [Find the Middle Element of a Linked List](https://www.baeldung.com/java-linked-list-middle-element) - [Find Substrings That Are Palindromes in Java](https://www.baeldung.com/java-palindrome-substrings) - [Find the Longest Substring without Repeating Characters](https://www.baeldung.com/java-longest-substring-without-repeated-characters) -- [Permutations of an Array in Java](https://www.baeldung.com/java-array-permutations) \ No newline at end of file +- [Permutations of an Array in Java](https://www.baeldung.com/java-array-permutations) +- [Find the Smallest Missing Integer in an Array](https://www.baeldung.com/java-smallest-missing-integer-in-array) +- More articles: [[<-- prev]](/algorithms-miscellaneous-3) [[next -->]](/algorithms-miscellaneous-5) diff --git a/algorithms-miscellaneous-4/src/main/java/com/baeldung/algorithms/smallestinteger/SmallestMissingPositiveInteger.java b/algorithms-miscellaneous-4/src/main/java/com/baeldung/algorithms/smallestinteger/SmallestMissingPositiveInteger.java new file mode 100644 index 0000000000..b08eea2a66 --- /dev/null +++ b/algorithms-miscellaneous-4/src/main/java/com/baeldung/algorithms/smallestinteger/SmallestMissingPositiveInteger.java @@ -0,0 +1,37 @@ +package com.baeldung.algorithms.smallestinteger; + +import java.util.Arrays; + +public class SmallestMissingPositiveInteger { + public static int searchInSortedArray(int[] input) { + for (int i = 0; i < input.length; i++) { + if (i != input[i]) { + return i; + } + } + + return input.length; + } + + public static int searchInUnsortedArraySortingFirst(int[] input) { + Arrays.sort(input); + return searchInSortedArray(input); + } + + public static int searchInUnsortedArrayBooleanArray(int[] input) { + boolean[] flags = new boolean[input.length]; + for (int number : input) { + if (number < flags.length) { + flags[number] = true; + } + } + + for (int i = 0; i < flags.length; i++) { + if (!flags[i]) { + return i; + } + } + + return flags.length; + } +} diff --git a/algorithms-miscellaneous-4/src/main/java/com/baeldung/algorithms/string/search/StringSearchAlgorithms.java b/algorithms-miscellaneous-4/src/main/java/com/baeldung/algorithms/string/search/StringSearchAlgorithms.java deleted file mode 100755 index 45ac53e039..0000000000 --- a/algorithms-miscellaneous-4/src/main/java/com/baeldung/algorithms/string/search/StringSearchAlgorithms.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.baeldung.algorithms.string.search; - -import java.math.BigInteger; -import java.util.Random; - -public class StringSearchAlgorithms { - public static long getBiggerPrime(int m) { - BigInteger prime = BigInteger.probablePrime(getNumberOfBits(m) + 1, new Random()); - return prime.longValue(); - } - - public static long getLowerPrime(long number) { - BigInteger prime = BigInteger.probablePrime(getNumberOfBits(number) - 1, new Random()); - return prime.longValue(); - } - - private static int getNumberOfBits(final int number) { - return Integer.SIZE - Integer.numberOfLeadingZeros(number); - } - - private static int getNumberOfBits(final long number) { - return Long.SIZE - Long.numberOfLeadingZeros(number); - } - - public static int simpleTextSearch(char[] pattern, char[] text) { - int patternSize = pattern.length; - int textSize = text.length; - - int i = 0; - - while ((i + patternSize) <= textSize) { - int j = 0; - while (text[i + j] == pattern[j]) { - j += 1; - if (j >= patternSize) - return i; - } - i += 1; - } - - return -1; - } - - public static int RabinKarpMethod(char[] pattern, char[] text) { - int patternSize = pattern.length; // m - int textSize = text.length; // n - - long prime = getBiggerPrime(patternSize); - - long r = 1; - for (int i = 0; i < patternSize - 1; i++) { - r *= 2; - r = r % prime; - } - - long[] t = new long[textSize]; - t[0] = 0; - - long pfinger = 0; - - for (int j = 0; j < patternSize; j++) { - t[0] = (2 * t[0] + text[j]) % prime; - pfinger = (2 * pfinger + pattern[j]) % prime; - } - - int i = 0; - boolean passed = false; - - int diff = textSize - patternSize; - for (i = 0; i <= diff; i++) { - if (t[i] == pfinger) { - passed = true; - for (int k = 0; k < patternSize; k++) { - if (text[i + k] != pattern[k]) { - passed = false; - break; - } - } - - if (passed) { - return i; - } - } - - if (i < diff) { - long value = 2 * (t[i] - r * text[i]) + text[i + patternSize]; - t[i + 1] = ((value % prime) + prime) % prime; - } - } - return -1; - - } - - public static int KnuthMorrisPrattSearch(char[] pattern, char[] text) { - int patternSize = pattern.length; // m - int textSize = text.length; // n - - int i = 0, j = 0; - - int[] shift = KnuthMorrisPrattShift(pattern); - - while ((i + patternSize) <= textSize) { - while (text[i + j] == pattern[j]) { - j += 1; - if (j >= patternSize) - return i; - } - - if (j > 0) { - i += shift[j - 1]; - j = Math.max(j - shift[j - 1], 0); - } else { - i++; - j = 0; - } - } - return -1; - } - - public static int[] KnuthMorrisPrattShift(char[] pattern) { - int patternSize = pattern.length; - - int[] shift = new int[patternSize]; - shift[0] = 1; - - int i = 1, j = 0; - - while ((i + j) < patternSize) { - if (pattern[i + j] == pattern[j]) { - shift[i + j] = i; - j++; - } else { - if (j == 0) - shift[i] = i + 1; - - if (j > 0) { - i = i + shift[j - 1]; - j = Math.max(j - shift[j - 1], 0); - } else { - i = i + 1; - j = 0; - } - } - } - return shift; - } - - public static int BoyerMooreHorspoolSimpleSearch(char[] pattern, char[] text) { - int patternSize = pattern.length; - int textSize = text.length; - - int i = 0, j = 0; - - while ((i + patternSize) <= textSize) { - j = patternSize - 1; - while (text[i + j] == pattern[j]) { - j--; - if (j < 0) - return i; - } - i++; - } - return -1; - } - - public static int BoyerMooreHorspoolSearch(char[] pattern, char[] text) { - - int shift[] = new int[256]; - - for (int k = 0; k < 256; k++) { - shift[k] = pattern.length; - } - - for (int k = 0; k < pattern.length - 1; k++) { - shift[pattern[k]] = pattern.length - 1 - k; - } - - int i = 0, j = 0; - - while ((i + pattern.length) <= text.length) { - j = pattern.length - 1; - - while (text[i + j] == pattern[j]) { - j -= 1; - if (j < 0) - return i; - } - - i = i + shift[text[i + pattern.length - 1]]; - - } - return -1; - } -} diff --git a/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/StringSearchAlgorithmsUnitTest.java b/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/StringSearchAlgorithmsUnitTest.java deleted file mode 100755 index dfe015aad2..0000000000 --- a/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/StringSearchAlgorithmsUnitTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.baeldung.algorithms; - - -import org.junit.Assert; -import org.junit.Test; - -import com.baeldung.algorithms.string.search.StringSearchAlgorithms; - -public class StringSearchAlgorithmsUnitTest { - - - @Test - public void testStringSearchAlgorithms(){ - String text = "This is some nice text."; - String pattern = "some"; - - int realPosition = text.indexOf(pattern); - Assert.assertTrue(realPosition == StringSearchAlgorithms.simpleTextSearch(pattern.toCharArray(), text.toCharArray())); - Assert.assertTrue(realPosition == StringSearchAlgorithms.RabinKarpMethod(pattern.toCharArray(), text.toCharArray())); - Assert.assertTrue(realPosition == StringSearchAlgorithms.KnuthMorrisPrattSearch(pattern.toCharArray(), text.toCharArray())); - Assert.assertTrue(realPosition == StringSearchAlgorithms.BoyerMooreHorspoolSimpleSearch(pattern.toCharArray(), text.toCharArray())); - Assert.assertTrue(realPosition == StringSearchAlgorithms.BoyerMooreHorspoolSearch(pattern.toCharArray(), text.toCharArray())); - } - -} diff --git a/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/smallestinteger/SmallestMissingPositiveIntegerUnitTest.java b/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/smallestinteger/SmallestMissingPositiveIntegerUnitTest.java new file mode 100644 index 0000000000..8bb7151b41 --- /dev/null +++ b/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/smallestinteger/SmallestMissingPositiveIntegerUnitTest.java @@ -0,0 +1,88 @@ +package com.baeldung.algorithms.smallestinteger; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class SmallestMissingPositiveIntegerUnitTest { + @Test + void givenArrayWithThreeMissing_whenSearchInSortedArray_thenThree() { + int[] input = new int[] {0, 1, 2, 4, 5}; + + int result = SmallestMissingPositiveInteger.searchInSortedArray(input); + + assertThat(result).isEqualTo(3); + } + + @Test + void givenArrayWithOneAndThreeMissing_whenSearchInSortedArray_thenOne() { + int[] input = new int[] {0, 2, 4, 5}; + + int result = SmallestMissingPositiveInteger.searchInSortedArray(input); + + assertThat(result).isEqualTo(1); + } + + @Test + void givenArrayWithoutMissingInteger_whenSearchInSortedArray_thenArrayLength() { + int[] input = new int[] {0, 1, 2, 3, 4, 5}; + + int result = SmallestMissingPositiveInteger.searchInSortedArray(input); + + assertThat(result).isEqualTo(input.length); + } + + @Test + void givenArrayWithThreeMissing_whenSearchInUnsortedArraySortingFirst_thenThree() { + int[] input = new int[] {1, 4, 0, 5, 2}; + + int result = SmallestMissingPositiveInteger.searchInUnsortedArraySortingFirst(input); + + assertThat(result).isEqualTo(3); + } + + @Test + void givenArrayWithOneAndThreeMissing_whenSearchInUnsortedArraySortingFirst_thenOne() { + int[] input = new int[] {4, 2, 0, 5}; + + int result = SmallestMissingPositiveInteger.searchInUnsortedArraySortingFirst(input); + + assertThat(result).isEqualTo(1); + } + + @Test + void givenArrayWithoutMissingInteger_whenSearchInUnsortedArraySortingFirst_thenArrayLength() { + int[] input = new int[] {4, 5, 1, 3, 0, 2}; + + int result = SmallestMissingPositiveInteger.searchInUnsortedArraySortingFirst(input); + + assertThat(result).isEqualTo(input.length); + } + + @Test + void givenArrayWithThreeMissing_whenSearchInUnsortedArrayBooleanArray_thenThree() { + int[] input = new int[] {1, 4, 0, 5, 2}; + + int result = SmallestMissingPositiveInteger.searchInUnsortedArrayBooleanArray(input); + + assertThat(result).isEqualTo(3); + } + + @Test + void givenArrayWithOneAndThreeMissing_whenSearchInUnsortedArrayBooleanArray_thenOne() { + int[] input = new int[] {4, 2, 0, 5}; + + int result = SmallestMissingPositiveInteger.searchInUnsortedArrayBooleanArray(input); + + assertThat(result).isEqualTo(1); + } + + @Test + void givenArrayWithoutMissingInteger_whenSearchInUnsortedArrayBooleanArray_thenArrayLength() { + int[] input = new int[] {4, 5, 1, 3, 0, 2}; + + int result = SmallestMissingPositiveInteger.searchInUnsortedArrayBooleanArray(input); + + assertThat(result).isEqualTo(input.length); + } +} \ No newline at end of file diff --git a/algorithms-miscellaneous-5/README.md b/algorithms-miscellaneous-5/README.md index 7ed71e61cc..27ab303210 100644 --- a/algorithms-miscellaneous-5/README.md +++ b/algorithms-miscellaneous-5/README.md @@ -1,5 +1,13 @@ -## Relevant articles: +## Algorithms - Miscellaneous + +This module contains articles about algorithms. Some classes of algorithms, e.g., [sorting](/../algorithms-sorting) and +[genetic algorithms](/../algorithms-genetic), have their own dedicated modules. + +### Relevant articles: - [Converting Between Byte Arrays and Hexadecimal Strings in Java](https://www.baeldung.com/java-byte-arrays-hex-strings) - [Reversing a Binary Tree in Java](https://www.baeldung.com/java-reversing-a-binary-tree) -- [Find If Two Numbers Are Relatively Prime in Java](https://www.baeldung.com/java-two-relatively-prime-numbers) \ No newline at end of file +- [Find If Two Numbers Are Relatively Prime in Java](https://www.baeldung.com/java-two-relatively-prime-numbers) +- [Knapsack Problem Implementation in Java](https://www.baeldung.com/java-knapsack) +- [How to Determine if a Binary Tree is Balanced](https://www.baeldung.com/java-balanced-binary-tree) +- More articles: [[<-- prev]](/../algorithms-miscellaneous-4) diff --git a/algorithms-miscellaneous-5/pom.xml b/algorithms-miscellaneous-5/pom.xml index d17f93e6e0..98a7f33474 100644 --- a/algorithms-miscellaneous-5/pom.xml +++ b/algorithms-miscellaneous-5/pom.xml @@ -17,6 +17,11 @@ commons-codec ${commons-codec.version} + + org.apache.commons + commons-math3 + ${commons-math3.version} + org.projectlombok lombok @@ -28,6 +33,7 @@ tradukisto ${tradukisto.version} + org.assertj assertj-core @@ -52,6 +58,7 @@ 1.0.1 3.9.0 1.11 + 3.6.1 \ No newline at end of file diff --git a/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/balancedbinarytree/BalancedBinaryTree.java b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/balancedbinarytree/BalancedBinaryTree.java new file mode 100644 index 0000000000..84180473e2 --- /dev/null +++ b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/balancedbinarytree/BalancedBinaryTree.java @@ -0,0 +1,33 @@ +package com.baeldung.algorithms.balancedbinarytree; + +public class BalancedBinaryTree { + + public static boolean isBalanced(Tree tree) { + return isBalancedRecursive(tree, -1).isBalanced; + } + + private static Result isBalancedRecursive(Tree tree, int depth) { + if (tree == null) { + return new Result(true, -1); + } + + Result leftSubtreeResult = isBalancedRecursive(tree.left(), depth + 1); + Result rightSubtreeResult = isBalancedRecursive(tree.right(), depth + 1); + + boolean isBalanced = Math.abs(leftSubtreeResult.height - rightSubtreeResult.height) <= 1; + boolean subtreesAreBalanced = leftSubtreeResult.isBalanced && rightSubtreeResult.isBalanced; + int height = Math.max(leftSubtreeResult.height, rightSubtreeResult.height) + 1; + + return new Result(isBalanced && subtreesAreBalanced, height); + } + + private static final class Result { + private final boolean isBalanced; + private final int height; + + private Result(boolean isBalanced, int height) { + this.isBalanced = isBalanced; + this.height = height; + } + } +} diff --git a/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/balancedbinarytree/Tree.java b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/balancedbinarytree/Tree.java new file mode 100644 index 0000000000..8e091408c9 --- /dev/null +++ b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/balancedbinarytree/Tree.java @@ -0,0 +1,34 @@ +package com.baeldung.algorithms.balancedbinarytree; + +public class Tree { + private final int value; + private final Tree left; + private final Tree right; + + public Tree(int value, Tree left, Tree right) { + this.value = value; + this.left = left; + this.right = right; + } + + public int value() { + return value; + } + + public Tree left() { + return left; + } + + public Tree right() { + return right; + } + + @Override + public String toString() { + return String.format("[%s, %s, %s]", + value, + left == null ? "null" : left.toString(), + right == null ? "null" : right.toString() + ); + } +} diff --git a/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/binarygap/BinaryGap.java b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/binarygap/BinaryGap.java new file mode 100644 index 0000000000..e31e9870a0 --- /dev/null +++ b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/binarygap/BinaryGap.java @@ -0,0 +1,17 @@ +package com.baeldung.algorithms.binarygap; + +public class BinaryGap { + static int calculateBinaryGap(int n) { + return calculateBinaryGap(n >>> Integer.numberOfTrailingZeros(n), 0, 0); + } + + static int calculateBinaryGap(int n, int current, int maximum) { + if (n == 0) { + return maximum; + } else if ((n & 1) == 0) { + return calculateBinaryGap(n >>> 1, current + 1, maximum); + } else { + return calculateBinaryGap(n >>> 1, 0, Math.max(maximum, current)); + } + } +} diff --git a/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/caesarcipher/CaesarCipher.java b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/caesarcipher/CaesarCipher.java new file mode 100644 index 0000000000..5ee913d251 --- /dev/null +++ b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/caesarcipher/CaesarCipher.java @@ -0,0 +1,83 @@ +package com.baeldung.algorithms.caesarcipher; + +import org.apache.commons.math3.stat.inference.ChiSquareTest; + +import java.util.Arrays; +import java.util.stream.IntStream; + +public class CaesarCipher { + private static final char LETTER_A = 'a'; + private static final char LETTER_Z = 'z'; + private static final int ALPHABET_SIZE = LETTER_Z - LETTER_A + 1; + private static final double[] ENGLISH_LETTERS_PROBABILITIES = {0.073, 0.009, 0.030, 0.044, 0.130, 0.028, 0.016, 0.035, 0.074, 0.002, 0.003, 0.035, 0.025, 0.078, 0.074, 0.027, 0.003, 0.077, 0.063, 0.093, 0.027, 0.013, 0.016, 0.005, 0.019, 0.001}; + + public String cipher(String message, int offset) { + StringBuilder result = new StringBuilder(); + + for (char character : message.toCharArray()) { + if (character != ' ') { + int originalAlphabetPosition = character - LETTER_A; + int newAlphabetPosition = (originalAlphabetPosition + offset) % ALPHABET_SIZE; + char newCharacter = (char) (LETTER_A + newAlphabetPosition); + result.append(newCharacter); + } else { + result.append(character); + } + } + + return result.toString(); + } + + public String decipher(String message, int offset) { + return cipher(message, ALPHABET_SIZE - (offset % ALPHABET_SIZE)); + } + + public int breakCipher(String message) { + return probableOffset(chiSquares(message)); + } + + private double[] chiSquares(String message) { + double[] expectedLettersFrequencies = expectedLettersFrequencies(message.length()); + + double[] chiSquares = new double[ALPHABET_SIZE]; + + for (int offset = 0; offset < chiSquares.length; offset++) { + String decipheredMessage = decipher(message, offset); + long[] lettersFrequencies = observedLettersFrequencies(decipheredMessage); + double chiSquare = new ChiSquareTest().chiSquare(expectedLettersFrequencies, lettersFrequencies); + chiSquares[offset] = chiSquare; + } + + return chiSquares; + } + + private long[] observedLettersFrequencies(String message) { + return IntStream.rangeClosed(LETTER_A, LETTER_Z) + .mapToLong(letter -> countLetter((char) letter, message)) + .toArray(); + } + + private long countLetter(char letter, String message) { + return message.chars() + .filter(character -> character == letter) + .count(); + } + + private double[] expectedLettersFrequencies(int messageLength) { + return Arrays.stream(ENGLISH_LETTERS_PROBABILITIES) + .map(probability -> probability * messageLength) + .toArray(); + } + + private int probableOffset(double[] chiSquares) { + int probableOffset = 0; + for (int offset = 0; offset < chiSquares.length; offset++) { + System.out.println(String.format("Chi-Square for offset %d: %.2f", offset, chiSquares[offset])); + if (chiSquares[offset] < chiSquares[probableOffset]) { + probableOffset = offset; + } + } + + return probableOffset; + } +} diff --git a/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/combinatorics/Combinatorics.java b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/combinatorics/Combinatorics.java new file mode 100644 index 0000000000..a5c4b325a4 --- /dev/null +++ b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/combinatorics/Combinatorics.java @@ -0,0 +1,67 @@ +package com.baeldung.algorithms.combinatorics; + +import java.util.*; + +import static java.util.Collections.swap; + +public class Combinatorics { + + public static List> permutations(List sequence) { + List> results = new ArrayList<>(); + permutationsInternal(sequence, results, 0); + return results; + } + + private static void permutationsInternal(List sequence, List> results, int index) { + if (index == sequence.size() - 1) { + results.add(new ArrayList<>(sequence)); + } + + for (int i = index; i < sequence.size(); i++) { + swap(sequence, i, index); + permutationsInternal(sequence, results, index + 1); + swap(sequence, i, index); + } + } + + public static List> combinations(List inputSet, int k) { + List> results = new ArrayList<>(); + combinationsInternal(inputSet, k, results, new ArrayList<>(), 0); + return results; + } + + private static void combinationsInternal( + List inputSet, int k, List> results, ArrayList accumulator, int index) { + int leftToAccumulate = k - accumulator.size(); + int possibleToAcculumate = inputSet.size() - index; + + if (accumulator.size() == k) { + results.add(new ArrayList<>(accumulator)); + } else if (leftToAccumulate <= possibleToAcculumate) { + combinationsInternal(inputSet, k, results, accumulator, index + 1); + + accumulator.add(inputSet.get(index)); + combinationsInternal(inputSet, k, results, accumulator, index + 1); + accumulator.remove(accumulator.size() - 1); + } + } + + public static List> powerSet(List sequence) { + List> results = new ArrayList<>(); + powerSetInternal(sequence, results, new ArrayList<>(), 0); + return results; + } + + private static void powerSetInternal( + List set, List> powerSet, List accumulator, int index) { + if (index == set.size()) { + powerSet.add(new ArrayList<>(accumulator)); + } else { + accumulator.add(set.get(index)); + + powerSetInternal(set, powerSet, accumulator, index + 1); + accumulator.remove(accumulator.size() - 1); + powerSetInternal(set, powerSet, accumulator, index + 1); + } + } +} diff --git a/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/knapsack/Knapsack.java b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/knapsack/Knapsack.java new file mode 100644 index 0000000000..61c3f05a95 --- /dev/null +++ b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/knapsack/Knapsack.java @@ -0,0 +1,36 @@ +package com.baeldung.algorithms.knapsack; + +public class Knapsack { + + public int knapsackRec(int[] w, int[] v, int n, int W) { + if (n <= 0) { + return 0; + } else if (w[n - 1] > W) { + return knapsackRec(w, v, n - 1, W); + } else { + return Math.max(knapsackRec(w, v, n - 1, W), v[n - 1] + knapsackRec(w, v, n - 1, W - w[n - 1])); + } + } + + public int knapsackDP(int[] w, int[] v, int n, int W) { + if (n <= 0 || W <= 0) { + return 0; + } + + int[][] m = new int[n + 1][W + 1]; + for (int j = 0; j <= W; j++) { + m[0][j] = 0; + } + + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= W; j++) { + if (w[i - 1] > j) { + m[i][j] = m[i - 1][j]; + } else { + m[i][j] = Math.max(m[i - 1][j], m[i - 1][j - w[i - 1]] + v[i - 1]); + } + } + } + return m[n][W]; + } +} diff --git a/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/balancedbinarytree/BalancedBinaryTreeUnitTest.java b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/balancedbinarytree/BalancedBinaryTreeUnitTest.java new file mode 100644 index 0000000000..25f313f991 --- /dev/null +++ b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/balancedbinarytree/BalancedBinaryTreeUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.algorithms.balancedbinarytree; + +import org.junit.Test; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +public class BalancedBinaryTreeUnitTest extends BinaryTreeDataProvider { + + @Test + public void givenBalancedTrees_whenCallingIsBalanced_ShouldReturnTrue() { + for (Tree tree : balancedTrees()) { + assertTrue(toString(tree) + " should be balanced", BalancedBinaryTree.isBalanced(tree)); + } + } + + @Test + public void givenUnbalancedTrees_whenCallingIsBalanced_ShouldReturnFalse() { + for (Tree tree : unbalancedTrees()) { + assertFalse(toString(tree) + " should not be balanced", BalancedBinaryTree.isBalanced(tree)); + } + } + + private String toString(Tree tree) { + return tree != null ? tree.toString() : "null"; + } +} diff --git a/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/balancedbinarytree/BinaryTreeDataProvider.java b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/balancedbinarytree/BinaryTreeDataProvider.java new file mode 100644 index 0000000000..3f4318afbc --- /dev/null +++ b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/balancedbinarytree/BinaryTreeDataProvider.java @@ -0,0 +1,69 @@ +package com.baeldung.algorithms.balancedbinarytree; + +import java.util.Arrays; +import java.util.Collection; + +class BinaryTreeDataProvider { + + static Collection balancedTrees() { + return Arrays.asList( + null, + leaf(1), + tree(1, leaf(2), leaf(3)), + tree( + 1, + leaf(2), + tree(3, leaf(4), null) + ), + tree( + 1, + tree( + 2, + tree(3, leaf(4), null), + leaf(5) + ), + tree( + 6, + leaf(7), + tree(8, null, leaf(9)) + ) + ) + ); + } + + static Collection unbalancedTrees() { + return Arrays.asList( + tree( + 1, + tree(2, leaf(3), null), + null + ), + tree( + 1, + tree( + 2, + tree(3, leaf(4), leaf(5)), + null + ), + tree(6, leaf(7), null) + ), + tree( + 1, + tree(2, leaf(3), null), + tree( + 4, + tree(5, leaf(6), leaf(7)), + null + ) + ) + ); + } + + private static Tree leaf(int value) { + return new Tree(value, null, null); + } + + private static Tree tree(int value, Tree left, Tree right) { + return new Tree(value, left, right); + } +} diff --git a/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/binarygap/BinaryGapUnitTest.java b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/binarygap/BinaryGapUnitTest.java new file mode 100644 index 0000000000..304d36e2bb --- /dev/null +++ b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/binarygap/BinaryGapUnitTest.java @@ -0,0 +1,34 @@ +package com.baeldung.algorithms.binarygap; + +import static com.baeldung.algorithms.binarygap.BinaryGap.calculateBinaryGap; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class BinaryGapUnitTest { + + @Test public void givenNoOccurrenceOfBoundedZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { + + int result = calculateBinaryGap(63); + assertEquals(0, result); + } + + @Test public void givenTrailingZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { + + int result = calculateBinaryGap(40); + assertEquals(1, result); + } + + @Test public void givenSingleOccurrenceOfBoundedZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { + + int result = calculateBinaryGap(9); + assertEquals(2, result); + } + + @Test public void givenMultipleOccurrenceOfBoundedZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { + + int result = calculateBinaryGap(145); + assertEquals(3, result); + } + +} diff --git a/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/caesarcipher/CaesarCipherUnitTest.java b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/caesarcipher/CaesarCipherUnitTest.java new file mode 100644 index 0000000000..c3a22a8978 --- /dev/null +++ b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/caesarcipher/CaesarCipherUnitTest.java @@ -0,0 +1,83 @@ +package com.baeldung.algorithms.caesarcipher; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class CaesarCipherUnitTest { + private static final String SENTENCE = "he told me i could never teach a llama to drive"; + private static final String SENTENCE_SHIFTED_THREE = "kh wrog ph l frxog qhyhu whdfk d oodpd wr gulyh"; + private static final String SENTENCE_SHIFTED_TEN = "ro dyvn wo s myevn xofob dokmr k vvkwk dy nbsfo"; + + private CaesarCipher algorithm = new CaesarCipher(); + + @Test + void givenSentenceAndShiftThree_whenCipher_thenCipheredMessageWithoutOverflow() { + String cipheredSentence = algorithm.cipher(SENTENCE, 3); + + assertThat(cipheredSentence) + .isEqualTo(SENTENCE_SHIFTED_THREE); + } + + @Test + void givenSentenceAndShiftTen_whenCipher_thenCipheredMessageWithOverflow() { + String cipheredSentence = algorithm.cipher(SENTENCE, 10); + + assertThat(cipheredSentence) + .isEqualTo(SENTENCE_SHIFTED_TEN); + } + + @Test + void givenSentenceAndShiftThirtySix_whenCipher_thenCipheredLikeTenMessageWithOverflow() { + String cipheredSentence = algorithm.cipher(SENTENCE, 36); + + assertThat(cipheredSentence) + .isEqualTo(SENTENCE_SHIFTED_TEN); + } + + @Test + void givenSentenceShiftedThreeAndShiftThree_whenDecipher_thenOriginalSentenceWithoutOverflow() { + String decipheredSentence = algorithm.decipher(SENTENCE_SHIFTED_THREE, 3); + + assertThat(decipheredSentence) + .isEqualTo(SENTENCE); + } + + @Test + void givenSentenceShiftedTenAndShiftTen_whenDecipher_thenOriginalSentenceWithOverflow() { + String decipheredSentence = algorithm.decipher(SENTENCE_SHIFTED_TEN, 10); + + assertThat(decipheredSentence) + .isEqualTo(SENTENCE); + } + + @Test + void givenSentenceShiftedTenAndShiftThirtySix_whenDecipher_thenOriginalSentenceWithOverflow() { + String decipheredSentence = algorithm.decipher(SENTENCE_SHIFTED_TEN, 36); + + assertThat(decipheredSentence) + .isEqualTo(SENTENCE); + } + + @Test + void givenSentenceShiftedThree_whenBreakCipher_thenOriginalSentence() { + int offset = algorithm.breakCipher(SENTENCE_SHIFTED_THREE); + + assertThat(offset) + .isEqualTo(3); + + assertThat(algorithm.decipher(SENTENCE_SHIFTED_THREE, offset)) + .isEqualTo(SENTENCE); + } + + @Test + void givenSentenceShiftedTen_whenBreakCipher_thenOriginalSentence() { + int offset = algorithm.breakCipher(SENTENCE_SHIFTED_TEN); + + assertThat(offset) + .isEqualTo(10); + + assertThat(algorithm.decipher(SENTENCE_SHIFTED_TEN, offset)) + .isEqualTo(SENTENCE); + } +} \ No newline at end of file diff --git a/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/combinatorics/CombinatoricsUnitTest.java b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/combinatorics/CombinatoricsUnitTest.java new file mode 100644 index 0000000000..95ffdec239 --- /dev/null +++ b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/combinatorics/CombinatoricsUnitTest.java @@ -0,0 +1,80 @@ +package com.baeldung.algorithms.combinatorics; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +public class CombinatoricsUnitTest { + + @Test + public void givenEmptySequence_whenCallingPermutations_ShouldReturnEmptyList() { + List sequence = Arrays.asList(); + + List> permutations = Combinatorics.permutations(sequence); + + assertEquals(0, permutations.size()); + } + + @Test + public void givenOneElementSequence_whenCallingPermutations_ShouldReturnPermutations() { + List sequence = Arrays.asList(1); + + List> permutations = Combinatorics.permutations(sequence); + + assertEquals(1, permutations.size()); + assertEquals(1, permutations.get(0).size()); + assertSame(1, permutations.get(0).get(0)); + } + + @Test + public void givenFourElementsSequence_whenCallingPermutations_ShouldReturnPermutations() { + List sequence = Arrays.asList(1, 2, 3, 4); + + List> permutations = Combinatorics.permutations(sequence); + + assertEquals(24, permutations.size()); + assertEquals(24, new HashSet<>(permutations).size()); + } + + @Test + public void givenTwoElements_whenCalling3Combinations_ShouldReturnEmptyList() { + List set = Arrays.asList(1, 2); + + List> combinations = Combinatorics.combinations(set, 3); + + assertEquals(0, combinations.size()); + } + + @Test + public void givenThreeElements_whenCalling3Combinations_ShouldReturnOneCombination() { + List set = Arrays.asList(1, 2, 3); + + List> combinations = Combinatorics.combinations(set, 3); + + assertEquals(1, combinations.size()); + assertEquals(combinations.get(0), Arrays.asList(1, 2, 3)); + } + + @Test + public void givenFourElements_whenCalling2Combinations_ShouldReturnCombinations() { + List set = Arrays.asList(1, 2, 3, 4); + + List> combinations = Combinatorics.combinations(set, 2); + + assertEquals(6, combinations.size()); + assertEquals(6, new HashSet<>(combinations).size()); + } + + @Test + public void givenFourElements_whenCallingPowerSet_ShouldReturn15Sets() { + List sequence = Arrays.asList('a', 'b', 'c', 'd'); + + List> combinations = Combinatorics.powerSet(sequence); + + assertEquals(16, combinations.size()); + } +} diff --git a/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/knapsack/KnapsackUnitTest.java b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/knapsack/KnapsackUnitTest.java new file mode 100644 index 0000000000..b168e6b1eb --- /dev/null +++ b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/knapsack/KnapsackUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.algorithms.knapsack; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class KnapsackUnitTest { + + @Test + public void givenWeightsandValues_whenCalculateMax_thenOutputCorrectResult() { + final int[] w = new int[] { 23, 26, 20, 18, 32, 27, 29, 26, 30, 27 }; + final int[] v = new int[] { 505, 352, 458, 220, 354, 414, 498, 545, 473, 543 }; + final int n = 10; + final int W = 67; + final Knapsack knapsack = new Knapsack(); + + assertEquals(1270, knapsack.knapsackRec(w, v, n, W)); + assertEquals(1270, knapsack.knapsackDP(w, v, n, W)); + } + + @Test + public void givenZeroItems_whenCalculateMax_thenOutputZero() { + final int[] w = new int[] {}; + final int[] v = new int[] {}; + final int n = 0; + final int W = 67; + final Knapsack knapsack = new Knapsack(); + + assertEquals(0, knapsack.knapsackRec(w, v, n, W)); + assertEquals(0, knapsack.knapsackDP(w, v, n, W)); + } + + @Test + public void givenZeroWeightLimit_whenCalculateMax_thenOutputZero() { + final int[] w = new int[] { 23, 26, 20, 18, 32, 27, 29, 26, 30, 27 }; + final int[] v = new int[] { 505, 352, 458, 220, 354, 414, 498, 545, 473, 543 }; + final int n = 10; + final int W = 0; + final Knapsack knapsack = new Knapsack(); + + assertEquals(0, knapsack.knapsackRec(w, v, n, W)); + assertEquals(0, knapsack.knapsackDP(w, v, n, W)); + } +} diff --git a/algorithms-searching/README.md b/algorithms-searching/README.md new file mode 100644 index 0000000000..d86c3e3de8 --- /dev/null +++ b/algorithms-searching/README.md @@ -0,0 +1,11 @@ +## Algorithms - Searching + +This module contains articles about searching algorithms. + +### Relevant articles: +- [Binary Search Algorithm in Java](https://www.baeldung.com/java-binary-search) +- [Depth First Search in Java](https://www.baeldung.com/java-depth-first-search) +- [Interpolation Search in Java](https://www.baeldung.com/java-interpolation-search) +- [Breadth-First Search Algorithm in Java](https://www.baeldung.com/java-breadth-first-search) +- [String Search Algorithms for Large Texts](https://www.baeldung.com/java-full-text-search-algorithms) +- [Monte Carlo Tree Search for Tic-Tac-Toe Game](https://www.baeldung.com/java-monte-carlo-tree-search) diff --git a/algorithms-searching/pom.xml b/algorithms-searching/pom.xml new file mode 100644 index 0000000000..6bd4b0233e --- /dev/null +++ b/algorithms-searching/pom.xml @@ -0,0 +1,37 @@ + + 4.0.0 + algorithms-searching + 0.0.1-SNAPSHOT + algorithms-searching + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.assertj + assertj-core + ${org.assertj.core.version} + test + + + + + algorithms-searching + + + src/main/resources + true + + + + + + 3.9.0 + + + \ No newline at end of file diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java similarity index 96% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java rename to algorithms-searching/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java index 5b2ac49d4e..82aefe282b 100644 --- a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java +++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java @@ -1,55 +1,55 @@ -package com.baeldung.algorithms.binarysearch; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public class BinarySearch { - - public int runBinarySearchIteratively(int[] sortedArray, int key, int low, int high) { - - int index = Integer.MAX_VALUE; - - while (low <= high) { - - int mid = (low + high) / 2; - - if (sortedArray[mid] < key) { - low = mid + 1; - } else if (sortedArray[mid] > key) { - high = mid - 1; - } else if (sortedArray[mid] == key) { - index = mid; - break; - } - } - return index; - } - - public int runBinarySearchRecursively(int[] sortedArray, int key, int low, int high) { - - int middle = (low + high) / 2; - if (high < low) { - return -1; - } - - if (key == sortedArray[middle]) { - return middle; - } else if (key < sortedArray[middle]) { - return runBinarySearchRecursively(sortedArray, key, low, middle - 1); - } else { - return runBinarySearchRecursively(sortedArray, key, middle + 1, high); - } - } - - public int runBinarySearchUsingJavaArrays(int[] sortedArray, Integer key) { - int index = Arrays.binarySearch(sortedArray, key); - return index; - } - - public int runBinarySearchUsingJavaCollections(List sortedList, Integer key) { - int index = Collections.binarySearch(sortedList, key); - return index; - } - -} +package com.baeldung.algorithms.binarysearch; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class BinarySearch { + + public int runBinarySearchIteratively(int[] sortedArray, int key, int low, int high) { + + int index = Integer.MAX_VALUE; + + while (low <= high) { + + int mid = (low + high) / 2; + + if (sortedArray[mid] < key) { + low = mid + 1; + } else if (sortedArray[mid] > key) { + high = mid - 1; + } else if (sortedArray[mid] == key) { + index = mid; + break; + } + } + return index; + } + + public int runBinarySearchRecursively(int[] sortedArray, int key, int low, int high) { + + int middle = (low + high) / 2; + if (high < low) { + return -1; + } + + if (key == sortedArray[middle]) { + return middle; + } else if (key < sortedArray[middle]) { + return runBinarySearchRecursively(sortedArray, key, low, middle - 1); + } else { + return runBinarySearchRecursively(sortedArray, key, middle + 1, high); + } + } + + public int runBinarySearchUsingJavaArrays(int[] sortedArray, Integer key) { + int index = Arrays.binarySearch(sortedArray, key); + return index; + } + + public int runBinarySearchUsingJavaCollections(List sortedList, Integer key) { + int index = Collections.binarySearch(sortedList, key); + return index; + } + +} diff --git a/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithm.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithm.java new file mode 100644 index 0000000000..9d301f9578 --- /dev/null +++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithm.java @@ -0,0 +1,54 @@ +package com.baeldung.algorithms.breadthfirstsearch; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +public class BreadthFirstSearchAlgorithm { + + private static final Logger LOGGER = LoggerFactory.getLogger(BreadthFirstSearchAlgorithm.class); + + public static Optional> search(T value, Tree root) { + Queue> queue = new ArrayDeque<>(); + queue.add(root); + + Tree currentNode; + while (!queue.isEmpty()) { + currentNode = queue.remove(); + LOGGER.info("Visited node with value: {}", currentNode.getValue()); + + if (currentNode.getValue().equals(value)) { + return Optional.of(currentNode); + } else { + queue.addAll(currentNode.getChildren()); + } + } + + return Optional.empty(); + } + + public static Optional> search(T value, Node start) { + Queue> queue = new ArrayDeque<>(); + queue.add(start); + + Node currentNode; + Set> alreadyVisited = new HashSet<>(); + + while (!queue.isEmpty()) { + currentNode = queue.remove(); + LOGGER.info("Visited node with value: {}", currentNode.getValue()); + + if (currentNode.getValue().equals(value)) { + return Optional.of(currentNode); + } else { + alreadyVisited.add(currentNode); + queue.addAll(currentNode.getNeighbors()); + queue.removeAll(alreadyVisited); + } + } + + return Optional.empty(); + } + +} diff --git a/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Node.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Node.java new file mode 100644 index 0000000000..54a589ae26 --- /dev/null +++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Node.java @@ -0,0 +1,31 @@ +package com.baeldung.algorithms.breadthfirstsearch; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class Node { + + private T value; + private Set> neighbors; + + public Node(T value) { + this.value = value; + this.neighbors = new HashSet<>(); + } + + public T getValue() { + return value; + } + + public Set> getNeighbors() { + return Collections.unmodifiableSet(neighbors); + } + + public void connect(Node node) { + if (this == node) throw new IllegalArgumentException("Can't connect node to itself"); + this.neighbors.add(node); + node.neighbors.add(this); + } + +} diff --git a/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Tree.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Tree.java new file mode 100644 index 0000000000..842d2837ff --- /dev/null +++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Tree.java @@ -0,0 +1,34 @@ +package com.baeldung.algorithms.breadthfirstsearch; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Tree { + + private T value; + private List> children; + + private Tree(T value) { + this.value = value; + this.children = new ArrayList<>(); + } + + public static Tree of(T value) { + return new Tree<>(value); + } + + public T getValue() { + return value; + } + + public List> getChildren() { + return Collections.unmodifiableList(children); + } + + public Tree addChild(T value) { + Tree newChild = new Tree<>(value); + children.add(newChild); + return newChild; + } +} diff --git a/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/BinaryTree.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/BinaryTree.java new file mode 100644 index 0000000000..a6019ea9f9 --- /dev/null +++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/BinaryTree.java @@ -0,0 +1,227 @@ +package com.baeldung.algorithms.dfs; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.Stack; + +public class BinaryTree { + + Node root; + + public void add(int value) { + root = addRecursive(root, value); + } + + private Node addRecursive(Node current, int value) { + + if (current == null) { + return new Node(value); + } + + if (value < current.value) { + current.left = addRecursive(current.left, value); + } else if (value > current.value) { + current.right = addRecursive(current.right, value); + } + + return current; + } + + public boolean isEmpty() { + return root == null; + } + + public int getSize() { + return getSizeRecursive(root); + } + + private int getSizeRecursive(Node current) { + return current == null ? 0 : getSizeRecursive(current.left) + 1 + getSizeRecursive(current.right); + } + + public boolean containsNode(int value) { + return containsNodeRecursive(root, value); + } + + private boolean containsNodeRecursive(Node current, int value) { + if (current == null) { + return false; + } + + if (value == current.value) { + return true; + } + + return value < current.value + ? containsNodeRecursive(current.left, value) + : containsNodeRecursive(current.right, value); + } + + public void delete(int value) { + root = deleteRecursive(root, value); + } + + private Node deleteRecursive(Node current, int value) { + if (current == null) { + return null; + } + + if (value == current.value) { + // Case 1: no children + if (current.left == null && current.right == null) { + return null; + } + + // Case 2: only 1 child + if (current.right == null) { + return current.left; + } + + if (current.left == null) { + return current.right; + } + + // Case 3: 2 children + int smallestValue = findSmallestValue(current.right); + current.value = smallestValue; + current.right = deleteRecursive(current.right, smallestValue); + return current; + } + if (value < current.value) { + current.left = deleteRecursive(current.left, value); + return current; + } + + current.right = deleteRecursive(current.right, value); + return current; + } + + private int findSmallestValue(Node root) { + return root.left == null ? root.value : findSmallestValue(root.left); + } + + public void traverseInOrder(Node node) { + if (node != null) { + traverseInOrder(node.left); + visit(node.value); + traverseInOrder(node.right); + } + } + + public void traversePreOrder(Node node) { + if (node != null) { + visit(node.value); + traversePreOrder(node.left); + traversePreOrder(node.right); + } + } + + public void traversePostOrder(Node node) { + if (node != null) { + traversePostOrder(node.left); + traversePostOrder(node.right); + visit(node.value); + } + } + + public void traverseLevelOrder() { + if (root == null) { + return; + } + + Queue nodes = new LinkedList<>(); + nodes.add(root); + + while (!nodes.isEmpty()) { + + Node node = nodes.remove(); + + System.out.print(" " + node.value); + + if (node.left != null) { + nodes.add(node.left); + } + + if (node.left != null) { + nodes.add(node.right); + } + } + } + + + public void traverseInOrderWithoutRecursion() { + Stack stack = new Stack(); + Node current = root; + stack.push(root); + while(! stack.isEmpty()) { + while(current.left != null) { + current = current.left; + stack.push(current); + } + current = stack.pop(); + visit(current.value); + if(current.right != null) { + current = current.right; + stack.push(current); + } + } + } + + public void traversePreOrderWithoutRecursion() { + Stack stack = new Stack(); + Node current = root; + stack.push(root); + while(! stack.isEmpty()) { + current = stack.pop(); + visit(current.value); + + if(current.right != null) + stack.push(current.right); + + if(current.left != null) + stack.push(current.left); + } + } + + public void traversePostOrderWithoutRecursion() { + Stack stack = new Stack(); + Node prev = root; + Node current = root; + stack.push(root); + + while (!stack.isEmpty()) { + current = stack.peek(); + boolean hasChild = (current.left != null || current.right != null); + boolean isPrevLastChild = (prev == current.right || (prev == current.left && current.right == null)); + + if (!hasChild || isPrevLastChild) { + current = stack.pop(); + visit(current.value); + prev = current; + } else { + if (current.right != null) { + stack.push(current.right); + } + if (current.left != null) { + stack.push(current.left); + } + } + } + } + + private void visit(int value) { + System.out.print(" " + value); + } + + class Node { + int value; + Node left; + Node right; + + Node(int value) { + this.value = value; + right = null; + left = null; + } + } +} diff --git a/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/Graph.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/Graph.java new file mode 100644 index 0000000000..d2cc723cf9 --- /dev/null +++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/Graph.java @@ -0,0 +1,74 @@ +package com.baeldung.algorithms.dfs; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +public class Graph { + + private Map> adjVertices; + + public Graph() { + this.adjVertices = new HashMap>(); + } + + public void addVertex(int vertex) { + adjVertices.putIfAbsent(vertex, new ArrayList<>()); + } + + public void addEdge(int src, int dest) { + adjVertices.get(src).add(dest); + } + + public void dfsWithoutRecursion(int start) { + Stack stack = new Stack(); + boolean[] isVisited = new boolean[adjVertices.size()]; + stack.push(start); + while (!stack.isEmpty()) { + int current = stack.pop(); + isVisited[current] = true; + visit(current); + for (int dest : adjVertices.get(current)) { + if (!isVisited[dest]) + stack.push(dest); + } + } + } + + public void dfs(int start) { + boolean[] isVisited = new boolean[adjVertices.size()]; + dfsRecursive(start, isVisited); + } + + private void dfsRecursive(int current, boolean[] isVisited) { + isVisited[current] = true; + visit(current); + for (int dest : adjVertices.get(current)) { + if (!isVisited[dest]) + dfsRecursive(dest, isVisited); + } + } + + public List topologicalSort(int start) { + LinkedList result = new LinkedList(); + boolean[] isVisited = new boolean[adjVertices.size()]; + topologicalSortRecursive(start, isVisited, result); + return result; + } + + private void topologicalSortRecursive(int current, boolean[] isVisited, LinkedList result) { + isVisited[current] = true; + for (int dest : adjVertices.get(current)) { + if (!isVisited[dest]) + topologicalSortRecursive(dest, isVisited, result); + } + result.addFirst(current); + } + + private void visit(int value) { + System.out.print(" " + value); + } +} diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearch.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearch.java similarity index 100% rename from algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearch.java rename to algorithms-searching/src/main/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearch.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/MonteCarloTreeSearch.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/MonteCarloTreeSearch.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/MonteCarloTreeSearch.java rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/MonteCarloTreeSearch.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/State.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/State.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/State.java rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/State.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/UCT.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/UCT.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/UCT.java rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/UCT.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Board.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Board.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Board.java rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Board.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Position.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Position.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Position.java rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Position.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tree/Node.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tree/Node.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tree/Node.java rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tree/Node.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tree/Tree.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tree/Tree.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tree/Tree.java rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tree/Tree.java diff --git a/algorithms-searching/src/main/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithms.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithms.java new file mode 100644 index 0000000000..16b45ed886 --- /dev/null +++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithms.java @@ -0,0 +1,194 @@ +package com.baeldung.algorithms.textsearch; + +import java.math.BigInteger; +import java.util.Random; + +public class TextSearchAlgorithms { + public static long getBiggerPrime(int m) { + BigInteger prime = BigInteger.probablePrime(getNumberOfBits(m) + 1, new Random()); + return prime.longValue(); + } + + public static long getLowerPrime(long number) { + BigInteger prime = BigInteger.probablePrime(getNumberOfBits(number) - 1, new Random()); + return prime.longValue(); + } + + private static int getNumberOfBits(final int number) { + return Integer.SIZE - Integer.numberOfLeadingZeros(number); + } + + private static int getNumberOfBits(final long number) { + return Long.SIZE - Long.numberOfLeadingZeros(number); + } + + public static int simpleTextSearch(char[] pattern, char[] text) { + int patternSize = pattern.length; + int textSize = text.length; + + int i = 0; + + while ((i + patternSize) <= textSize) { + int j = 0; + while (text[i + j] == pattern[j]) { + j += 1; + if (j >= patternSize) + return i; + } + i += 1; + } + + return -1; + } + + public static int RabinKarpMethod(char[] pattern, char[] text) { + int patternSize = pattern.length; // m + int textSize = text.length; // n + + long prime = getBiggerPrime(patternSize); + + long r = 1; + for (int i = 0; i < patternSize - 1; i++) { + r *= 2; + r = r % prime; + } + + long[] t = new long[textSize]; + t[0] = 0; + + long pfinger = 0; + + for (int j = 0; j < patternSize; j++) { + t[0] = (2 * t[0] + text[j]) % prime; + pfinger = (2 * pfinger + pattern[j]) % prime; + } + + int i = 0; + boolean passed = false; + + int diff = textSize - patternSize; + for (i = 0; i <= diff; i++) { + if (t[i] == pfinger) { + passed = true; + for (int k = 0; k < patternSize; k++) { + if (text[i + k] != pattern[k]) { + passed = false; + break; + } + } + + if (passed) { + return i; + } + } + + if (i < diff) { + long value = 2 * (t[i] - r * text[i]) + text[i + patternSize]; + t[i + 1] = ((value % prime) + prime) % prime; + } + } + return -1; + + } + + public static int KnuthMorrisPrattSearch(char[] pattern, char[] text) { + int patternSize = pattern.length; // m + int textSize = text.length; // n + + int i = 0, j = 0; + + int[] shift = KnuthMorrisPrattShift(pattern); + + while ((i + patternSize) <= textSize) { + while (text[i + j] == pattern[j]) { + j += 1; + if (j >= patternSize) + return i; + } + + if (j > 0) { + i += shift[j - 1]; + j = Math.max(j - shift[j - 1], 0); + } else { + i++; + j = 0; + } + } + return -1; + } + + public static int[] KnuthMorrisPrattShift(char[] pattern) { + int patternSize = pattern.length; + + int[] shift = new int[patternSize]; + shift[0] = 1; + + int i = 1, j = 0; + + while ((i + j) < patternSize) { + if (pattern[i + j] == pattern[j]) { + shift[i + j] = i; + j++; + } else { + if (j == 0) + shift[i] = i + 1; + + if (j > 0) { + i = i + shift[j - 1]; + j = Math.max(j - shift[j - 1], 0); + } else { + i = i + 1; + j = 0; + } + } + } + return shift; + } + + public static int BoyerMooreHorspoolSimpleSearch(char[] pattern, char[] text) { + int patternSize = pattern.length; + int textSize = text.length; + + int i = 0, j = 0; + + while ((i + patternSize) <= textSize) { + j = patternSize - 1; + while (text[i + j] == pattern[j]) { + j--; + if (j < 0) + return i; + } + i++; + } + return -1; + } + + public static int BoyerMooreHorspoolSearch(char[] pattern, char[] text) { + + int shift[] = new int[256]; + + for (int k = 0; k < 256; k++) { + shift[k] = pattern.length; + } + + for (int k = 0; k < pattern.length - 1; k++) { + shift[pattern[k]] = pattern.length - 1 - k; + } + + int i = 0, j = 0; + + while ((i + pattern.length) <= text.length) { + j = pattern.length - 1; + + while (text[i + j] == pattern[j]) { + j -= 1; + if (j < 0) + return i; + } + + i = i + shift[text[i + pattern.length - 1]]; + + } + return -1; + } +} diff --git a/core-java-modules/core-java-datetime/src/main/resources/logback.xml b/algorithms-searching/src/main/resources/logback.xml similarity index 100% rename from core-java-modules/core-java-datetime/src/main/resources/logback.xml rename to algorithms-searching/src/main/resources/logback.xml diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java similarity index 94% rename from algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java rename to algorithms-searching/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java index 826682d373..eb3fb4f718 100644 --- a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java +++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java @@ -1,43 +1,41 @@ -package com.baeldung.algorithms.binarysearch; - -import java.util.Arrays; -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; -import com.baeldung.algorithms.binarysearch.BinarySearch; - -public class BinarySearchUnitTest { - - int[] sortedArray = { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; - int key = 6; - int expectedIndexForSearchKey = 7; - int low = 0; - int high = sortedArray.length - 1; - List sortedList = Arrays.asList(0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9); - - @Test - public void givenASortedArrayOfIntegers_whenBinarySearchRunIterativelyForANumber_thenGetIndexOfTheNumber() { - BinarySearch binSearch = new BinarySearch(); - Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchIteratively(sortedArray, key, low, high)); - } - - @Test - public void givenASortedArrayOfIntegers_whenBinarySearchRunRecursivelyForANumber_thenGetIndexOfTheNumber() { - BinarySearch binSearch = new BinarySearch(); - Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchRecursively(sortedArray, key, low, high)); - } - - @Test - public void givenASortedArrayOfIntegers_whenBinarySearchRunUsingArraysClassStaticMethodForANumber_thenGetIndexOfTheNumber() { - BinarySearch binSearch = new BinarySearch(); - Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaArrays(sortedArray, key)); - } - - @Test - public void givenASortedListOfIntegers_whenBinarySearchRunUsingCollectionsClassStaticMethodForANumber_thenGetIndexOfTheNumber() { - BinarySearch binSearch = new BinarySearch(); - Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaCollections(sortedList, key)); - } - -} +package com.baeldung.algorithms.binarysearch; + +import java.util.Arrays; +import java.util.List; +import org.junit.Assert; +import org.junit.Test; + +public class BinarySearchUnitTest { + + int[] sortedArray = { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; + int key = 6; + int expectedIndexForSearchKey = 7; + int low = 0; + int high = sortedArray.length - 1; + List sortedList = Arrays.asList(0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9); + + @Test + public void givenASortedArrayOfIntegers_whenBinarySearchRunIterativelyForANumber_thenGetIndexOfTheNumber() { + BinarySearch binSearch = new BinarySearch(); + Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchIteratively(sortedArray, key, low, high)); + } + + @Test + public void givenASortedArrayOfIntegers_whenBinarySearchRunRecursivelyForANumber_thenGetIndexOfTheNumber() { + BinarySearch binSearch = new BinarySearch(); + Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchRecursively(sortedArray, key, low, high)); + } + + @Test + public void givenASortedArrayOfIntegers_whenBinarySearchRunUsingArraysClassStaticMethodForANumber_thenGetIndexOfTheNumber() { + BinarySearch binSearch = new BinarySearch(); + Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaArrays(sortedArray, key)); + } + + @Test + public void givenASortedListOfIntegers_whenBinarySearchRunUsingCollectionsClassStaticMethodForANumber_thenGetIndexOfTheNumber() { + BinarySearch binSearch = new BinarySearch(); + Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaCollections(sortedList, key)); + } + +} diff --git a/algorithms-searching/src/test/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithmUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithmUnitTest.java new file mode 100644 index 0000000000..aa22fc5353 --- /dev/null +++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithmUnitTest.java @@ -0,0 +1,86 @@ +package com.baeldung.algorithms.breadthfirstsearch; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class BreadthFirstSearchAlgorithmUnitTest { + + private Tree root; + private Tree rootFirstChild; + private Tree depthMostChild; + private Tree rootSecondChild; + + private Node start; + private Node firstNeighbor; + private Node firstNeighborNeighbor; + private Node secondNeighbor; + + @Test + void givenTree_whenSearchTen_thenRoot() { + initTree(); + assertThat(BreadthFirstSearchAlgorithm.search(10, root)).isPresent().contains(root); + } + + @Test + void givenTree_whenSearchThree_thenDepthMostValue() { + initTree(); + assertThat(BreadthFirstSearchAlgorithm.search(3, root)).isPresent().contains(depthMostChild); + } + + @Test + void givenTree_whenSearchFour_thenRootSecondChild() { + initTree(); + assertThat(BreadthFirstSearchAlgorithm.search(4, root)).isPresent().contains(rootSecondChild); + } + + @Test + void givenTree_whenSearchFive_thenNotFound() { + initTree(); + assertThat(BreadthFirstSearchAlgorithm.search(5, root)).isEmpty(); + } + + private void initTree() { + root = Tree.of(10); + rootFirstChild = root.addChild(2); + depthMostChild = rootFirstChild.addChild(3); + rootSecondChild = root.addChild(4); + } + + @Test + void givenNode_whenSearchTen_thenStart() { + initNode(); + assertThat(BreadthFirstSearchAlgorithm.search(10, firstNeighborNeighbor)).isPresent().contains(start); + } + + @Test + void givenNode_whenSearchThree_thenNeighborNeighbor() { + initNode(); + assertThat(BreadthFirstSearchAlgorithm.search(3, firstNeighborNeighbor)).isPresent().contains(firstNeighborNeighbor); + } + + @Test + void givenNode_whenSearchFour_thenSecondNeighbor() { + initNode(); + assertThat(BreadthFirstSearchAlgorithm.search(4, firstNeighborNeighbor)).isPresent().contains(secondNeighbor); + } + + @Test + void givenNode_whenSearchFive_thenNotFound() { + initNode(); + assertThat(BreadthFirstSearchAlgorithm.search(5, firstNeighborNeighbor)).isEmpty(); + } + + private void initNode() { + start = new Node<>(10); + firstNeighbor = new Node<>(2); + start.connect(firstNeighbor); + + firstNeighborNeighbor = new Node<>(3); + firstNeighbor.connect(firstNeighborNeighbor); + firstNeighborNeighbor.connect(start); + + secondNeighbor = new Node<>(4); + start.connect(secondNeighbor); + } +} \ No newline at end of file diff --git a/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/BinaryTreeUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/BinaryTreeUnitTest.java new file mode 100644 index 0000000000..076da14f81 --- /dev/null +++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/BinaryTreeUnitTest.java @@ -0,0 +1,136 @@ +package com.baeldung.algorithms.dfs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class BinaryTreeUnitTest { + + @Test + public void givenABinaryTree_WhenAddingElements_ThenTreeNotEmpty() { + + BinaryTree bt = createBinaryTree(); + + assertTrue(!bt.isEmpty()); + } + + @Test + public void givenABinaryTree_WhenAddingElements_ThenTreeContainsThoseElements() { + + BinaryTree bt = createBinaryTree(); + + assertTrue(bt.containsNode(6)); + assertTrue(bt.containsNode(4)); + + assertFalse(bt.containsNode(1)); + } + + @Test + public void givenABinaryTree_WhenAddingExistingElement_ThenElementIsNotAdded() { + + BinaryTree bt = createBinaryTree(); + + int initialSize = bt.getSize(); + + assertTrue(bt.containsNode(3)); + bt.add(3); + assertEquals(initialSize, bt.getSize()); + } + + @Test + public void givenABinaryTree_WhenLookingForNonExistingElement_ThenReturnsFalse() { + + BinaryTree bt = createBinaryTree(); + + assertFalse(bt.containsNode(99)); + } + + @Test + public void givenABinaryTree_WhenDeletingElements_ThenTreeDoesNotContainThoseElements() { + + BinaryTree bt = createBinaryTree(); + + assertTrue(bt.containsNode(9)); + bt.delete(9); + assertFalse(bt.containsNode(9)); + } + + @Test + public void givenABinaryTree_WhenDeletingNonExistingElement_ThenTreeDoesNotDelete() { + + BinaryTree bt = createBinaryTree(); + + int initialSize = bt.getSize(); + + assertFalse(bt.containsNode(99)); + bt.delete(99); + assertFalse(bt.containsNode(99)); + assertEquals(initialSize, bt.getSize()); + } + + @Test + public void it_deletes_the_root() { + int value = 12; + BinaryTree bt = new BinaryTree(); + bt.add(value); + + assertTrue(bt.containsNode(value)); + bt.delete(value); + assertFalse(bt.containsNode(value)); + } + + @Test + public void givenABinaryTree_WhenTraversingInOrder_ThenPrintValues() { + + BinaryTree bt = createBinaryTree(); + + bt.traverseInOrder(bt.root); + System.out.println(); + bt.traverseInOrderWithoutRecursion(); + } + + @Test + public void givenABinaryTree_WhenTraversingPreOrder_ThenPrintValues() { + + BinaryTree bt = createBinaryTree(); + + bt.traversePreOrder(bt.root); + System.out.println(); + bt.traversePreOrderWithoutRecursion(); + } + + @Test + public void givenABinaryTree_WhenTraversingPostOrder_ThenPrintValues() { + + BinaryTree bt = createBinaryTree(); + + bt.traversePostOrder(bt.root); + System.out.println(); + bt.traversePostOrderWithoutRecursion(); + } + + @Test + public void givenABinaryTree_WhenTraversingLevelOrder_ThenPrintValues() { + + BinaryTree bt = createBinaryTree(); + + bt.traverseLevelOrder(); + } + + private BinaryTree createBinaryTree() { + BinaryTree bt = new BinaryTree(); + + bt.add(6); + bt.add(4); + bt.add(8); + bt.add(3); + bt.add(5); + bt.add(7); + bt.add(9); + + return bt; + } + +} diff --git a/data-structures/src/test/java/com/baeldung/graph/GraphUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java similarity index 92% rename from data-structures/src/test/java/com/baeldung/graph/GraphUnitTest.java rename to algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java index 09b92115d2..715bb55fcb 100644 --- a/data-structures/src/test/java/com/baeldung/graph/GraphUnitTest.java +++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java @@ -1,7 +1,8 @@ -package com.baeldung.graph; +package com.baeldung.algorithms.dfs; import java.util.List; +import com.baeldung.algorithms.dfs.Graph; import org.junit.Test; public class GraphUnitTest { diff --git a/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java similarity index 100% rename from algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java rename to algorithms-searching/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java index 8ad962055e..cabedcefad 100644 --- a/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java +++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java @@ -1,10 +1,10 @@ package com.baeldung.algorithms.interpolationsearch; -import static org.junit.jupiter.api.Assertions.assertEquals; - import org.junit.Before; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class InterpolationSearchUnitTest { private int[] myData; diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java similarity index 100% rename from algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java rename to algorithms-searching/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java diff --git a/algorithms-searching/src/test/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithmsUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithmsUnitTest.java new file mode 100644 index 0000000000..543ccb912f --- /dev/null +++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithmsUnitTest.java @@ -0,0 +1,23 @@ +package com.baeldung.algorithms.textsearch; + + +import org.junit.Assert; +import org.junit.Test; + +public class TextSearchAlgorithmsUnitTest { + + + @Test + public void testStringSearchAlgorithms() { + String text = "This is some nice text."; + String pattern = "some"; + + int realPosition = text.indexOf(pattern); + Assert.assertTrue(realPosition == TextSearchAlgorithms.simpleTextSearch(pattern.toCharArray(), text.toCharArray())); + Assert.assertTrue(realPosition == TextSearchAlgorithms.RabinKarpMethod(pattern.toCharArray(), text.toCharArray())); + Assert.assertTrue(realPosition == TextSearchAlgorithms.KnuthMorrisPrattSearch(pattern.toCharArray(), text.toCharArray())); + Assert.assertTrue(realPosition == TextSearchAlgorithms.BoyerMooreHorspoolSimpleSearch(pattern.toCharArray(), text.toCharArray())); + Assert.assertTrue(realPosition == TextSearchAlgorithms.BoyerMooreHorspoolSearch(pattern.toCharArray(), text.toCharArray())); + } + +} diff --git a/algorithms-sorting/README.md b/algorithms-sorting/README.md index f19705f113..15a5ec6e02 100644 --- a/algorithms-sorting/README.md +++ b/algorithms-sorting/README.md @@ -12,3 +12,9 @@ This module contains articles about sorting algorithms. - [Shell Sort in Java](https://www.baeldung.com/java-shell-sort) - [Counting Sort in Java](https://www.baeldung.com/java-counting-sort) - [Sorting Strings by Contained Numbers in Java](https://www.baeldung.com/java-sort-strings-contained-numbers) +- [How an In-Place Sorting Algorithm Works](https://www.baeldung.com/java-in-place-sorting) +- [Selection Sort in Java](https://www.baeldung.com/java-selection-sort) +- [Sorting Strings by Contained Numbers in Java](https://www.baeldung.com/java-sort-strings-contained-numbers) +- [Radix Sort in Java](https://www.baeldung.com/java-radix-sort) +- [Sorting a String Alphabetically in Java](https://www.baeldung.com/java-sort-string-alphabetically) +- [Bucket Sort in Java](https://www.baeldung.com/java-bucket-sort) diff --git a/algorithms-sorting/pom.xml b/algorithms-sorting/pom.xml index b25adf05a8..5bb19a8069 100644 --- a/algorithms-sorting/pom.xml +++ b/algorithms-sorting/pom.xml @@ -28,6 +28,12 @@ ${lombok.version} provided + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter-api.version} + test + org.assertj assertj-core @@ -52,6 +58,7 @@ 3.6.1 3.9.0 1.11 + 5.3.1 \ No newline at end of file diff --git a/java-strings/src/main/java/com/baeldung/string/sorting/AnagramValidator.java b/algorithms-sorting/src/main/java/com/baeldung/algorithms/stringsort/AnagramValidator.java similarity index 93% rename from java-strings/src/main/java/com/baeldung/string/sorting/AnagramValidator.java rename to algorithms-sorting/src/main/java/com/baeldung/algorithms/stringsort/AnagramValidator.java index c4f684383d..67b5e5facc 100644 --- a/java-strings/src/main/java/com/baeldung/string/sorting/AnagramValidator.java +++ b/algorithms-sorting/src/main/java/com/baeldung/algorithms/stringsort/AnagramValidator.java @@ -1,4 +1,4 @@ -package com.baeldung.string.sorting; +package com.baeldung.algorithms.stringsort; import java.util.Arrays; diff --git a/java-strings/src/test/java/com/baeldung/string/sorting/AnagramValidatorUnitTest.java b/algorithms-sorting/src/test/java/com/baeldung/algorithms/stringsort/AnagramValidatorUnitTest.java similarity index 86% rename from java-strings/src/test/java/com/baeldung/string/sorting/AnagramValidatorUnitTest.java rename to algorithms-sorting/src/test/java/com/baeldung/algorithms/stringsort/AnagramValidatorUnitTest.java index 07d31c7187..25fc274dd8 100644 --- a/java-strings/src/test/java/com/baeldung/string/sorting/AnagramValidatorUnitTest.java +++ b/algorithms-sorting/src/test/java/com/baeldung/algorithms/stringsort/AnagramValidatorUnitTest.java @@ -1,12 +1,10 @@ -package com.baeldung.string.sorting; +package com.baeldung.algorithms.stringsort; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertFalse; - import org.junit.jupiter.api.Test; -import com.baeldung.string.sorting.AnagramValidator; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; class AnagramValidatorUnitTest { diff --git a/java-strings/src/test/java/com/baeldung/string/sorting/SortStringUnitTest.java b/algorithms-sorting/src/test/java/com/baeldung/algorithms/stringsort/SortStringUnitTest.java similarity index 94% rename from java-strings/src/test/java/com/baeldung/string/sorting/SortStringUnitTest.java rename to algorithms-sorting/src/test/java/com/baeldung/algorithms/stringsort/SortStringUnitTest.java index 90d1dad554..226de64f07 100644 --- a/java-strings/src/test/java/com/baeldung/string/sorting/SortStringUnitTest.java +++ b/algorithms-sorting/src/test/java/com/baeldung/algorithms/stringsort/SortStringUnitTest.java @@ -1,9 +1,9 @@ -package com.baeldung.string.sorting; - -import java.util.Arrays; +package com.baeldung.algorithms.stringsort; import org.junit.jupiter.api.Test; +import java.util.Arrays; + import static org.assertj.core.api.Assertions.assertThat; class SortStringUnitTest { diff --git a/animal-sniffer-mvn-plugin/pom.xml b/animal-sniffer-mvn-plugin/pom.xml index 55e37e2ec4..fd8f6d3d8c 100644 --- a/animal-sniffer-mvn-plugin/pom.xml +++ b/animal-sniffer-mvn-plugin/pom.xml @@ -1,7 +1,6 @@ 4.0.0 - com.baeldung animal-sniffer-mvn-plugin 1.0-SNAPSHOT animal-sniffer-mvn-plugin diff --git a/apache-avro/pom.xml b/apache-avro/pom.xml index e6fb4d24ff..6baae9c541 100644 --- a/apache-avro/pom.xml +++ b/apache-avro/pom.xml @@ -14,12 +14,6 @@ - - junit - junit - ${junit.version} - test - org.slf4j slf4j-simple @@ -46,15 +40,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - ${compiler-plugin.version} - - ${java.version} - ${java.version} - - org.apache.avro avro-maven-plugin @@ -79,8 +64,6 @@ - UTF-8 - 3.5 1.8.2 1.7.25 diff --git a/apache-fop/pom.xml b/apache-fop/pom.xml index 879eb4f111..150756d51d 100644 --- a/apache-fop/pom.xml +++ b/apache-fop/pom.xml @@ -1,7 +1,6 @@ 4.0.0 - com.baeldung apache-fop 0.1-SNAPSHOT apache-fop diff --git a/apache-fop/src/test/resources/input.xml b/apache-fop/src/test/resources/input.xml deleted file mode 100644 index a8266f3f5c..0000000000 --- a/apache-fop/src/test/resources/input.xml +++ /dev/null @@ -1,1674 +0,0 @@ - -
- - Bootstrap a Web Application with Spring 4 - - - - - - Return to Content - - - - - - Contents - - - Table of Contents - - - 1. Overview - - - 2. The Maven pom.xml - - - 3. The Java based Web Configuration - - - 4. Conclusion - - - If you're new here, you may want to get my "REST APIs with Spring" eBook. Thanks for visiting! - - - -
- <anchor xml:id="Table_of_Contents"/><emphasis role="bold">Table of Contents</emphasis> - - - 1. Overview - - - 2. The Maven pom.xml - - -     2.1. Justification of the cglib dependency - - -     2.2. The cglib dependency in Spring 3.2 and beyond - - - 3. The Java based web configuration - - -    3.1. The web.xml - - - 4. Conclusion - - -
- <anchor xml:id="dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> - The tutorial illustrates how to Bootstrap a Web Application with Spring and also discusses how to make the jump from XML to Java without having to completely migrate the entire XML configuration. -
-
- <anchor xml:id="dbdoclet.2_The_Maven_pomxml"/><emphasis role="bold">2. The Maven pom.xml</emphasis> - <project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation=" - http://maven.apache.org/POM/4.0.0 - http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org</groupId> - <artifactId>rest</artifactId> - <version>0.0.1-SNAPSHOT</version> - <packaging>war</packaging> - - <dependencies> - - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-webmvc</artifactId> - <version>${spring.version}</version> - <exclusions> - <exclusion> - <artifactId>commons-logging</artifactId> - <groupId>commons-logging</groupId> - </exclusion> - </exclusions> - </dependency> - - </dependencies> - - <build> - <finalName>rest</finalName> - - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.1</version> - <configuration> - <source>1.6</source> - <target>1.6</target> - <encoding>UTF-8</encoding> - </configuration> - </plugin> - </plugins> - </build> - - <properties> - <spring.version>4.0.5.RELEASE</spring.version> - </properties> - -</project> -
- <emphasis role="bold">2.1. The cglib dependency before Spring 3.2</emphasis> - You may wonder why cglib is a dependency – it turns out there is a valid reason to include it – the entire configuration cannot function without it. If removed, Spring will throw: - Caused by: java.lang.IllegalStateException: CGLIB is required to process @Configuration classes. Either add CGLIB to the classpath or remove the following @Configuration bean definitions - The reason this happens is explained by the way Spring deals with @Configuration classes. These classes are effectively beans, and because of this they need to be aware of the Context, and respect scope and other bean semantics. This is achieved by dynamically creating a cglib proxy with this awareness for each @Configuration class, hence the cglib dependency. - Also, because of this, there are a few restrictions for Configuration annotated classes: - - - Configuration classes should not be final - - - They should have a constructor with no arguments - - -
-
- <emphasis role="bold">2.2. The cglib dependency in Spring 3.2 and beyond</emphasis> - Starting with Spring 3.2, it is no longer necessary to add cglib as an explicit dependency. This is because Spring is in now inlining cglib – which will ensure that all class based proxying functionality will work out of the box with Spring 3.2. - The new cglib code is placed under the Spring package: org.springframework.cglib (replacing the original net.sf.cglib). The reason for the package change is to avoid conflicts with any cglib versions already existing on the classpath. - Also, the new cglib 3.0 is now used, upgraded from the older 2.2 dependency (see this JIRA issue for more details). - Finally, now that Spring 4.0 is out in the wild, changes like this one (removing the cglib dependency) are to be expected with Java 8 just around the corner – you can watch this Spring Jira to keep track of the Spring support, and the Java 8 Resources page to keep tabs on the that. -
-
-
- <anchor xml:id="dbdoclet.3_The_Java_based_Web_Configuration"/><emphasis role="bold">3. The Java based Web Configuration</emphasis> - @Configuration -@ImportResource( { "classpath*:/rest_config.xml" } ) -@ComponentScan( basePackages = "org.rest" ) -@PropertySource({ "classpath:rest.properties", "classpath:web.properties" }) -public class AppConfig{ - - @Bean -   public static PropertySourcesPlaceholderConfigurer properties() { -   return new PropertySourcesPlaceholderConfigurer(); -   } -} - First, the @Configuration annotation – this is the main artifact used by the Java based Spring configuration; it is itself meta-annotated with @Component, which makes the annotated classes standard beans and as such, also candidates for component scanning. The main purpose of @Configuration classes is to be sources of bean definitions for the Spring IoC Container. For a more detailed description, see the official docs. - Then, @ImportResource is used to import the existing XML based Spring configuration. This may be configuration which is still being migrated from XML to Java, or simply legacy configuration that you wish to keep. Either way, importing it into the Container is essential for a successful migration, allowing small steps without to much risk. The equivalent XML annotation that is replaced is: - <import resource=”classpath*:/rest_config.xml” /> - Moving on to @ComponentScan – this configures the component scanning directive, effectively replacing the XML: - <context:component-scan base-package="org.rest" /> - As of Spring 3.1, the @Configuration are excluded from classpath scanning by default – see this JIRA issue. Before Spring 3.1 though, these classes should have been excluded explicitly: - excludeFilters = { @ComponentScan.Filter( Configuration.class ) } - The @Configuration classes should not be autodiscovered because they are already specified and used by the Container – allowing them to be rediscovered and introduced into the Spring context will result in the following error: - Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name ‘webConfig’ for bean class [org.rest.spring.AppConfig] conflicts with existing, non-compatible bean definition of same name and class [org.rest.spring.AppConfig] - And finally, using the @Bean annotation to configure the properties support – PropertySourcesPlaceholderConfigurer is initialized in a @Bean annotated method, indicating it will produce a Spring bean managed by the Container. This new configuration has replaced the following XML: - <context:property-placeholder -location="classpath:persistence.properties, classpath:web.properties" -ignore-unresolvable="true"/> - For a more in depth discussion on why it was necessary to manually register the PropertySourcesPlaceholderConfigurer bean, see the Properties with Spring Tutorial. -
- <emphasis role="bold">3.1. The web.xml</emphasis> - <?xml version="1.0" encoding="UTF-8"?> -<web-app xmlns=" - http://java.sun.com/xml/ns/javaee" -     xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" -     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" -    xsi:schemaLocation=" - http://java.sun.com/xml/ns/javaee - http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" -    id="rest" version="3.0"> - - <context-param> - <param-name>contextClass</param-name> - <param-value> - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - </param-value> - </context-param> - <context-param> - <param-name>contextConfigLocation</param-name> - <param-value>org.rest.spring.root</param-value> - </context-param> - <listener> - <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> - </listener> - - <servlet> - <servlet-name>rest</servlet-name> - <servlet-class> - org.springframework.web.servlet.DispatcherServlet - </servlet-class> - <init-param> - <param-name>contextClass</param-name> - <param-value> - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - </param-value> - </init-param> - <init-param> - <param-name>contextConfigLocation</param-name> - <param-value>org.rest.spring.rest</param-value> - </init-param> - <load-on-startup>1</load-on-startup> - </servlet> - <servlet-mapping> - <servlet-name>rest</servlet-name> - <url-pattern>/api/*</url-pattern> - </servlet-mapping> - - <welcome-file-list> - <welcome-file /> - </welcome-file-list> - -</web-app> - First, the root context is defined and configured to use AnnotationConfigWebApplicationContext instead of the default XmlWebApplicationContext. The newer AnnotationConfigWebApplicationContext accepts @Configuration annotated classes as input for the Container configuration and is needed in order to set up the Java based context. Unlike XmlWebApplicationContext, it assumes no default configuration class locations, so the “contextConfigLocation”init-param for the Servlet must be set. This will point to the java package where the @Configuration classes are located; the fully qualified name(s) of the classes are also supported. - Next, the DispatcherServlet is configured to use the same kind of context, with the only difference that it’s loading configuration classes out of a different package. - Other than this, the web.xml doesn’t really change from a XML to a Java based configuration. -
-
-
- <anchor xml:id="dbdoclet.4_Conclusion"/><emphasis role="bold">4. Conclusion</emphasis> - The presented approach allows for a smooth migration of the Spring configuration from XML to Java, mixing the old and the new. This is important for older projects, which may have a lot of XML based configuration that cannot be migrated all at once. - This way, in a migration, the XML beans can be ported in small increments. - In the next article on REST with Spring, I cover setting up MVC in the project, configuration of the HTTP status codes, payload marshalling and content negotiation. - The implementation of this Bootstrap a Spring Web App Tutorial can be downloaded as a working sample project. - This is an Eclipse based project, so it should be easy to import and run as it is. - -   - - - - - - - - - java, Spring - - - - - - - - - - - © 2014 Baeldung. All Rights Reserved. - - - - - - - -
-
-
- -
- - Build a REST API with Spring 4 and Java Config - - - - - - Return to Content - - - - - - Contents - - - Table of Contents - - - 1. Overview - - - 2. Understanding REST in Spring - - - 3. The Java configuration - - - 4. Testing the Spring context - - - 5. The Controller - - - 6. Mapping the HTTP response codes - - - 7. Additional Maven dependencies - - - 8. Conclusion - - - If you're new here, you may want to get my "REST APIs with Spring" eBook. Thanks for visiting! - - -   - -
- <anchor xml:id="Table_of_Contents"/><emphasis role="bold">Table of Contents</emphasis> - - - 1. Overview - - - 2. Understanding REST in Spring - - - 3. The Java configuration - - - 4. Testing the Spring context - - - 5. The Controller - - - 6. Mapping the HTTP response codes - - -     6.1. Unmapped requests - - -     6.2. Valid, mapped requests - - -     6.3. Client error - - -     6.4. Using @ExceptionHandler - - - 7. Additional Maven dependencies - - - 8. Conclusion - - -
- <anchor xml:id="dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> - This article shows how to set up REST in Spring – the Controller and HTTP response codes, configuration of payload marshalling and content negotiation. -
-
- <anchor xml:id="dbdoclet.2_Understanding_REST_in_Spring"/><emphasis role="bold">2. Understanding REST in Spring</emphasis> - The Spring framework supports 2 ways of creating RESTful services: - - - using MVC with ModelAndView - - - using HTTP message converters - - - The ModelAndView approach is older and much better documented, but also more verbose and configuration heavy. It tries to shoehorn the REST paradigm into the old model, which is not without problems. The Spring team understood this and provided first-class REST support starting with Spring 3.0. - The new approach, based on HttpMessageConverterand annotations, is much more lightweight and easy to implement. Configuration is minimal and it provides sensible defaults for what you would expect from a RESTful service. It is however newer and a a bit on the light side concerning documentation; what’s , the reference doesn’t go out of it’s way to make the distinction and the tradeoffs between the two approaches as clear as they should be. Nevertheless, this is the way RESTful services should be build after Spring 3.0. -
-
- <anchor xml:id="dbdoclet.3_The_Java_configuration"/><emphasis role="bold">3. The Java configuration</emphasis> - - @Configuration -@EnableWebMvc -public class WebConfig{ - // -} - The new @EnableWebMvc annotation does a number of useful things – specifically, in the case of REST, it detect the existence of Jackson and JAXB 2 on the classpath and automatically creates and registers default JSON and XML converters. The functionality of the annotation is equivalent to the XML version: - <mvc:annotation-driven /> - This is a shortcut, and though it may be useful in many situations, it’s not perfect. When more complex configuration is needed, remove the annotation and extend WebMvcConfigurationSupport directly. -
-
- <anchor xml:id="dbdoclet.4_Testing_the_Spring_context"/><emphasis role="bold">4. Testing the Spring context</emphasis> - Starting with Spring 3.1, we get first-class testing support for @Configuration classes: - @RunWith( SpringJUnit4ClassRunner.class ) -@ContextConfiguration( classes = { ApplicationConfig.class, PersistenceConfig.class }, - loader = AnnotationConfigContextLoader.class ) -public class SpringTest{ - - @Test - public void whenSpringContextIsInstantiated_thenNoExceptions(){ - // When - } -} - The Java configuration classes are simply specified with the @ContextConfiguration annotation and the new AnnotationConfigContextLoader loads the bean definitions from the @Configuration classes. - Notice that the WebConfig configuration class was not included in the test because it needs to run in a Servlet context, which is not provided. -
-
- <anchor xml:id="dbdoclet.5_The_Controller"/><emphasis role="bold">5. The Controller</emphasis> - The @Controller is the central artifact in the entire Web Tier of the RESTful API. For the purpose of this post, the controller is modeling a simple REST resource – Foo: - @Controller -@RequestMapping( value = "/foos" ) -class FooController{ - - @Autowired - IFooService service; - - @RequestMapping( method = RequestMethod.GET ) - @ResponseBody - public List< Foo > findAll(){ - return service.findAll(); - } - - @RequestMapping( value = "/{id}", method = RequestMethod.GET ) - @ResponseBody - public Foo findOne( @PathVariable( "id" ) Long id ){ - return RestPreconditions.checkFound( service.findOne( id ) ); - } - - @RequestMapping( method = RequestMethod.POST ) - @ResponseStatus( HttpStatus.CREATED ) - @ResponseBody - public Long create( @RequestBody Foo resource ){ - Preconditions.checkNotNull( resource ); - return service.create( resource ); - } - - @RequestMapping( value = "/{id}", method = RequestMethod.PUT ) - @ResponseStatus( HttpStatus.OK ) - public void update( @PathVariable( "id" ) Long id, @RequestBody Foo resource ){ - Preconditions.checkNotNull( resource ); - RestPreconditions.checkNotNull( service.getById( resource.getId() ) ); - service.update( resource ); - } - - @RequestMapping( value = "/{id}", method = RequestMethod.DELETE ) - @ResponseStatus( HttpStatus.OK ) - public void delete( @PathVariable( "id" ) Long id ){ - service.deleteById( id ); - } - -} - You may have noticed I’m using a very simple, guava style RestPreconditions utility: - public class RestPreconditions { - public static <T> T checkFound(final T resource) { - if (resource == null) { - throw new MyResourceNotFoundException(); - } - return resource; - } -} - The Controller implementation is non-public – this is because it doesn’t need to be. Usually the controller is the last in the chain of dependencies – it receives HTTP requests from the Spring front controller (the DispathcerServlet) and simply delegate them forward to a service layer. If there is no use case where the controller has to be injected or manipulated through a direct reference, then I prefer not to declare it as public. - The request mappings are straightforward – as with any controller, the actual value of the mapping as well as the HTTP method are used to determine the target method for the request. @RequestBody will bind the parameters of the method to the body of the HTTP request, whereas @ResponseBody does the same for the response and return type. They also ensure that the resource will be marshalled and unmarshalled using the correct HTTP converter. Content negotiation will take place to choose which one of the active converters will be used, based mostly on the Accept header, although other HTTP headers may be used to determine the representation as well. -
-
- <anchor xml:id="dbdoclet.6_Mapping_the_HTTP_response_codes"/><emphasis role="bold">6. Mapping the HTTP response codes</emphasis> - The status codes of the HTTP response are one of the most important parts of the REST service, and the subject can quickly become very complex. Getting these right can be what makes or breaks the service. -
- <emphasis role="bold">6.1. Unmapped requests</emphasis> - If Spring MVC receives a request which doesn’t have a mapping, it considers the request not to be allowed and returns a 405 METHOD NOT ALLOWED back to the client. It is also good practice to include the Allow HTTP header when returning a 405 to the client, in order to specify which operations are allowed. This is the standard behavior of Spring MVC and does not require any additional configuration. -
-
- <emphasis role="bold">6.2. Valid, mapped requests</emphasis> - For any request that does have a mapping, Spring MVC considers the request valid and responds with 200 OK if no other status code is specified otherwise. It is because of this that controller declares different @ResponseStatus for the create, update and delete actions but not for get, which should indeed return the default 200 OK. -
-
- <emphasis role="bold">6.3. Client error</emphasis> - In case of a client error, custom exceptions are defined and mapped to the appropriate error codes. Simply throwing these exceptions from any of the layers of the web tier will ensure Spring maps the corresponding status code on the HTTP response. - @ResponseStatus( value = HttpStatus.BAD_REQUEST ) -public class BadRequestException extends RuntimeException{ - // -} -@ResponseStatus( value = HttpStatus.NOT_FOUND ) -public class ResourceNotFoundException extends RuntimeException{ - // -} - These exceptions are part of the REST API and, as such, should only be used in the appropriate layers corresponding to REST; if for instance a DAO/DAL layer exist, it should not use the exceptions directly. Note also that these are not checked exceptions but runtime exceptions – in line with Spring practices and idioms. -
-
- <emphasis role="bold">6.4. Using @ExceptionHandler</emphasis> - Another option to map custom exceptions on specific status codes is to use the @ExceptionHandler annotation in the controller. The problem with that approach is that the annotation only applies to the controller in which it is defined, not to the entire Spring Container, which means that it needs to be declared in each controller individually. This quickly becomes cumbersome, especially in more complex applications which many controllers. There are a few JIRA issues opened with Spring at this time to handle this and other related limitations: SPR-8124, SPR-7278, SPR-8406. -
-
-
- <anchor xml:id="dbdoclet.7_Additional_Maven_dependencies"/><emphasis role="bold">7. Additional Maven dependencies</emphasis><emphasis role="bold"></emphasis> - In addition to the spring-webmvc dependency required for the standard web application, we’ll need to set up content marshalling and unmarshalling for the REST API: - <dependencies> - <dependency> -   <groupId>com.fasterxml.jackson.core</groupId> -    <artifactId>jackson-databind</artifactId> -   <version>${jackson.version}</version> - </dependency> - <dependency> - <groupId>javax.xml.bind</groupId> - <artifactId>jaxb-api</artifactId> - <version>${jaxb-api.version}</version> - <scope>runtime</scope> - </dependency> -</dependencies> - -<properties> - <jackson.version>2.4.0</jackson.version> - <jaxb-api.version>2.2.11</jaxb-api.version> -</properties> - These are the libraries used to convert the representation of the REST resource to either JSON or XML. -
-
- <anchor xml:id="dbdoclet.8_Conclusion"/><emphasis role="bold">8. Conclusion</emphasis> - This tutorial illustrated how to implement and configure a REST Service using Spring 4 and Java based configuration, discussing HTTP response codes, basic Content Negotiation and marshaling. - In the next articles of the series I will focus on Discoverability of the API, advanced content negotiation and working with additional representations of a Resource. - The implementation of this Spring REST API Tutorial can be downloaded as a working sample project. - This is an Eclipse based project, so it should be easy to import and run as it is. - - - - - - - - - - java, REST, Spring, testing - - - - - - - - - - - © 2014 Baeldung. All Rights Reserved. - - - - - - - - - -
-
-
- -
- - Spring Security for a REST API - - - - - - Return to Content - - - - - - Contents - - - Table of Contents - - - 1. Overview - - - 2. Spring Security in the web.xml - - - 3. The Security Configuration - - - 4. Maven and other trouble - - - 5. Conclusion - - - - - -
- <anchor xml:id="Table_of_Contents"/><emphasis role="bold">Table of Contents</emphasis> - - - 1. Overview - - - 2. Introducing Spring Security in the web.xml - - - 3. The Security Configuration - - -     3.1. The basics - - -     3.2. The Entry Point - - -     3.3. The Login - - -     3.4. Authentication should return 200 instead of 301 - - -     3.5. Failed Authentication should return 401 instead of 302 - - -     3.6. The Authentication Manager and Provider - - -     3.7. Finally – Authentication against the running REST Service - - - 4. Maven and other trouble - - - 5. Conclusion - - -
- <anchor xml:id="dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> - This tutorial shows how to Secure a REST Service using Spring and Spring Security 3.1 with Java based configuration. The article will focus on how to set up the Security Configuration specifically for the REST API using a Login and Cookie approach. -
-
- <anchor xml:id="dbdoclet.2_Spring_Security_in_the_webxml"/><emphasis role="bold">2. Spring Security in the web.xml</emphasis> - The architecture of Spring Security is based entirely on Servlet Filters and, as such, comes before Spring MVC in regards to the processing of HTTP requests. Keeping this in mind, to begin with, a filter needs to be declared in the web.xml of the application: - <filter> - <filter-name>springSecurityFilterChain</filter-name> - <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> -</filter> -<filter-mapping> - <filter-name>springSecurityFilterChain</filter-name> - <url-pattern>/*</url-pattern> -</filter-mapping> - The filter must necessarily be named ‘springSecurityFilterChain’  to match the default bean created by Spring Security in the container. - Note that the defined filter is not the actual class implementing the security logic but a DelegatingFilterProxy with the purpose of delegating the Filter’s methods to an internal bean. This is done so that the target bean can still benefit from the Spring context lifecycle and flexibility. - The URL pattern used to configure the Filter is /* even though the entire web service is mapped to /api/* so that the security configuration has the option to secure other possible mappings as well, if required. -
-
- <anchor xml:id="dbdoclet.3_The_Security_Configuration"/><emphasis role="bold">3. The Security Configuration</emphasis> - <?xml version="1.0" encoding="UTF-8"?> -<beans:beans - xmlns="http://www.springframework.org/schema/security" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:beans="http://www.springframework.org/schema/beans" - xmlns:sec="http://www.springframework.org/schema/security" - xsi:schemaLocation=" - http://www.springframework.org/schema/security - http://www.springframework.org/schema/security/spring-security-3.2.xsd - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> - - <http entry-point-ref="restAuthenticationEntryPoint"> - <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN"/> - - <form-login - authentication-success-handler-ref="mySuccessHandler" - authentication-failure-handler-ref="myFailureHandler" - /> - - <logout /> - </http> - - <beans:bean id="mySuccessHandler" - class="org.rest.security.MySavedRequestAwareAuthenticationSuccessHandler"/> - <beans:bean id="myFailureHandler" - class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"/> - - <authentication-manager alias="authenticationManager"> - <authentication-provider> - <user-service> - <user name="temporary" password="temporary" authorities="ROLE_ADMIN"/> - <user name="user" password="user" authorities="ROLE_USER"/> - </user-service> - </authentication-provider> - </authentication-manager> - -</beans:beans> - Most of the configuration is done using the security namespace – for this to be enabled, the schema locations must be defined and pointed to the correct 3.1 or 3.2 XSD versions. The namespace is designed so that it expresses the common uses of Spring Security while still providing hooks raw beans to accommodate more advanced scenarios. >> Signup for my upcoming Video Course on Building a REST API with Spring 4 -
- <emphasis role="bold">3.1. The <http> element</emphasis> - The <http> element is the main container element for HTTP security configuration. In the current implementation, it only secured a single mapping: /api/admin/**. Note that the mapping is relative to the root context of the web application, not to the rest Servlet; this is because the entire security configuration lives in the root Spring context and not in the child context of the Servlet. -
-
- <emphasis role="bold">3.2. The Entry Point</emphasis> - In a standard web application, the authentication process may be automatically triggered when the client tries to access a secured resource without being authenticated – this is usually done by redirecting to a login page so that the user can enter credentials. However, for a REST Web Service this behavior doesn’t make much sense – Authentication should only be done by a request to the correct URI and all other requests should simply fail with a 401 UNAUTHORIZED status code if the user is not authenticated. - Spring Security handles this automatic triggering of the authentication process with the concept of an Entry Point – this is a required part of the configuration, and can be injected via the entry-point-ref attribute of the <http> element. Keeping in mind that this functionality doesn’t make sense in the context of the REST Service, the new custom entry point is defined to simply return 401 whenever it is triggered: - @Component( "restAuthenticationEntryPoint" ) -public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{ - - @Override - public void commence( HttpServletRequest request, HttpServletResponse response, - AuthenticationException authException ) throws IOException{ - response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized" ); - } -} - A quick sidenote here is that the 401 is sent without the WWW-Authenticate header, as required by the HTTP Spec – we can of course set the value manually if we need to. -
-
- <emphasis role="bold">3.3. The Login Form for REST</emphasis> - There are multiple ways to do Authentication for a REST API – one of the default Spring Security provides is Form Login – which uses an authentication processing filter – org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter. - The <form-login> element will create this filter and will also allow us to set our custom authentication success handler on it. This can also be done manually by using the <custom-filter> element to register a filter at the position FORM_LOGIN_FILTER – but the namespace support is flexible enough. - Note that for a standard web application, the auto-config attribute of the <http> element is shorthand syntax for some useful security configuration. While this may be appropriate for some very simple configurations, it doesn’t fit and should not be used for a REST API. -
-
- <emphasis role="bold">3.4. Authentication should return 200 instead of 301</emphasis> - By default, form login will answer a successful authentication request with a 301 MOVED PERMANENTLY status code; this makes sense in the context of an actual login form which needs to redirect after login. For a RESTful web service however, the desired response for a successful authentication should be 200 OK. - This is done by injecting a custom authentication success handler in the form login filter, to replace the default one. The new handler implements the exact same login as the default org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler with one notable difference – the redirect logic is removed: - public class MySavedRequestAwareAuthenticationSuccessHandler - extends SimpleUrlAuthenticationSuccessHandler { - - private RequestCache requestCache = new HttpSessionRequestCache(); - - @Override - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, - Authentication authentication) throws ServletException, IOException { - SavedRequest savedRequest = requestCache.getRequest(request, response); - - if (savedRequest == null) { - clearAuthenticationAttributes(request); - return; - } - String targetUrlParam = getTargetUrlParameter(); - if (isAlwaysUseDefaultTargetUrl() || - (targetUrlParam != null && - StringUtils.hasText(request.getParameter(targetUrlParam)))) { - requestCache.removeRequest(request, response); - clearAuthenticationAttributes(request); - return; - } - - clearAuthenticationAttributes(request); - } - - public void setRequestCache(RequestCache requestCache) { - this.requestCache = requestCache; - } -} -
-
- <emphasis role="bold">3.5. Failed Authentication should return 401 instead of 302</emphasis> - Similarly – we configured the authentication failure handler – same way we did with the success handler. - Luckily – in this case, we don’t need to actually define a new class for this handler – the standard implementation – SimpleUrlAuthenticationFailureHandler – does just fine. - The only difference is that – now that we’re defining this explicitly in our XML config – it’s not going to get a default defaultFailureUrl from Spring – and so it won’t redirect. -
-
- <emphasis role="bold">3.6. The Authentication Manager and Provider</emphasis> - The authentication process uses an in-memory provider to perform authentication – this is meant to simplify the configuration as a production implementation of these artifacts is outside the scope of this post. -
-
- <emphasis role="bold">3.7 Finally – Authentication against the running REST Service</emphasis> - Now let’s see how we can authenticate against the REST API – the URL for login is /j_spring_security_check – and a simple curl command performing login would be: - curl -i -X POST -d j_username=user -d j_password=userPass -http://localhost:8080/spring-security-rest/j_spring_security_check - This request will return the Cookie which will then be used by any subsequent request against the REST Service. - We can use curl to authentication and store the cookie it receives in a file: - curl -i -X POST -d j_username=user -d j_password=userPass -c /opt/cookies.txt -http://localhost:8080/spring-security-rest/j_spring_security_check - Then we can use the cookie from the file to do further authenticated requests: - curl -i --header "Accept:application/json" -X GET -b /opt/cookies.txt -http://localhost:8080/spring-security-rest/api/foos - This authenticated request will correctly result in a 200 OK: - HTTP/1.1 200 OK -Server: Apache-Coyote/1.1 -Content-Type: application/json;charset=UTF-8 -Transfer-Encoding: chunked -Date: Wed, 24 Jul 2013 20:31:13 GMT - -[{"id":0,"name":"JbidXc"}] -
-
-
- <anchor xml:id="dbdoclet.4_Maven_and_other_trouble"/><emphasis role="bold">4. Maven and other trouble</emphasis> - The Spring core dependencies necessary for a web application and for the REST Service have been discussed in detail. For security, we’ll need to add: spring-security-web and spring-security-config – all of these have also been covered in the Maven for Spring Security tutorial. - It’s worth paying close attention to the way Maven will resolve the older Spring dependencies – the resolution strategy will start causing problems once the security artifacts are added to the pom. To address this problem, some of the core dependencies will need to be overridden in order to keep them at the right version. -
-
- <anchor xml:id="dbdoclet.5_Conclusion"/><emphasis role="bold">5. Conclusion</emphasis> - This post covered the basic security configuration and implementation for a RESTful Service using Spring Security 3.1, discussing the web.xml, the security configuration, the HTTP status codes for the authentication process and the Maven resolution of the security artifacts. - The implementation of this Spring Security REST Tutorial can be downloaded as a working sample project.This is an Eclipse based project, so it should be easy to import and run as it is. - - - - - - - - - - REST, security, Spring - - - - - - - - - - - © 2014 Baeldung. All Rights Reserved. - - - - - - - - - -
-
-
- -
- - Spring Security Basic Authentication - - - - - - Return to Content - - - - - - Contents - - - 1. Overview - - - 2. The Spring Security Configuration - - - 3. Consuming The Secured Application - - - 4. Further Configuration – The Entry Point - - - 5. The Maven Dependencies - - - 6. Conclusion - - - If you're new here, you may want to get my "REST APIs with Spring" eBook. Thanks for visiting! - - - -
- <anchor xml:id="dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> - This tutorial shows how to set up, configure and customize Basic Authentication with Spring. We’re going to built on top of the simple Spring MVC example, and secure the UI of the MVC application with the Basic Auth mechanism provided by Spring Security. -
- <anchor xml:id="dbdoclet.2_The_Spring_Security_Configuration"/><emphasis role="bold">2. The Spring Security Configuration</emphasis> - The Configuration for Spring Security is still XML: - <?xml version="1.0" encoding="UTF-8"?> -<beans:beans xmlns="http://www.springframework.org/schema/security" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:beans="http://www.springframework.org/schema/beans" - xsi:schemaLocation=" - http://www.springframework.org/schema/security - http://www.springframework.org/schema/security/spring-security-3.1.xsd - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> - - <http use-expressions="true"> - <intercept-url pattern="/**" access="isAuthenticated()" /> - - <http-basic /> - </http> - - <authentication-manager> - <authentication-provider> - <user-service> - <user name="user1" password="user1Pass" authorities="ROLE_USER" /> - </user-service> - </authentication-provider> - </authentication-manager> - -</beans:beans> - This is one of the last pieces of configuration in Spring that still need XML – Java Configuration for Spring Security is still a work in progress. - What is relevant here is the <http-basic> element inside the main <http> element of the configuration – this is enough to enable Basic Authentication for the entire application. The Authentication Manager is not the focus of this tutorial, so we are using an in memory manager with the user and password defined in plaintext. - The web.xml of the web application enabling Spring Security has already been discussed in the Spring Logout tutorial. -
-
- <anchor xml:id="dbdoclet.3_Consuming_The_Secured_Application"/><emphasis role="bold">3. Consuming The Secured Application</emphasis> - The curl command is our go to tool for consuming the secured application. - First, let’s try to request the /homepage.html without providing any security credentials: - curl -i http://localhost:8080/spring-security-mvc-basic-auth/homepage.html - We get back the expected 401 Unauthorized and the Authentication Challenge: - HTTP/1.1 401 Unauthorized -Server: Apache-Coyote/1.1 -Set-Cookie: JSESSIONID=E5A8D3C16B65A0A007CFAACAEEE6916B; Path=/spring-security-mvc-basic-auth/; HttpOnly -WWW-Authenticate: Basic realm="Spring Security Application" -Content-Type: text/html;charset=utf-8 -Content-Length: 1061 -Date: Wed, 29 May 2013 15:14:08 GMT - The browser would interpret this challenge and prompt us for credentials with a simple dialog, but since we’re using curl, this isn’t the case. - Now, let’s request the same resource – the homepage – but provide the credentials to access it as well: - curl -i --user user1:user1Pass http://localhost:8080/spring-security-mvc-basic-auth/homepage.html - Now, the response from the server is 200 OK along with a Cookie: - HTTP/1.1 200 OK -Server: Apache-Coyote/1.1 -Set-Cookie: JSESSIONID=301225C7AE7C74B0892887389996785D; Path=/spring-security-mvc-basic-auth/; HttpOnly -Content-Type: text/html;charset=ISO-8859-1 -Content-Language: en-US -Content-Length: 90 -Date: Wed, 29 May 2013 15:19:38 GMT - From the browser, the application can be consumed normally – the only difference is that a login page is no longer a hard requirement since all browsers support Basic Authentication and use a dialog to prompt the user for credentials. -
-
- <anchor xml:id="dbdoclet.4_Further_Configuration_8211_The_Entry_Point"/><emphasis role="bold">4. Further Configuration – </emphasis><emphasis role="bold">The Entry Point</emphasis> - By default, the BasicAuthenticationEntryPoint provisioned by Spring Security returns a full html page for a 401 Unauthorized response back to the client. This html representation of the error renders well in a browser, but it not well suited for other scenarios, such as a REST API where a json representation may be preferred. - The namespace is flexible enough for this new requirement as well – to address this – the entry point can be overridden: - <http-basic entry-point-ref="myBasicAuthenticationEntryPoint" /> - The new entry point is defined as a standard bean: - @Component -public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint { - - @Override - public void commence - (HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx) - throws IOException, ServletException { - response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\""); - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - PrintWriter writer = response.getWriter(); - writer.println("HTTP Status 401 - " + authEx.getMessage()); - } - - @Override - public void afterPropertiesSet() throws Exception { - setRealmName("Baeldung"); - super.afterPropertiesSet(); - } -} - By writing directly to the HTTP Response we now have full control over the format of the response body. -
-
- <anchor xml:id="dbdoclet.5_The_Maven_Dependencies"/><emphasis role="bold">5. The Maven Dependencies</emphasis> - The Maven dependencies for Spring Security have been discussed before in the Spring Security with Maven article – we will need both spring-security-web and spring-security-config available at runtime. -
-
- <anchor xml:id="dbdoclet.6_Conclusion"/><emphasis role="bold">6. Conclusion</emphasis> - In this example we secured an MVC application with Spring Security and Basic Authentication. We discussed the XML configuration and we consumed the application with simple curl commands. Finally took control of the exact error message format – moving from the standard HTML error page to a custom text or json format. - The implementation of this Spring tutorial can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is. When the project runs locally, the sample html can be accessed at: - http://localhost:8080/spring-security-mvc-basic-auth/homepage.html - - - - - - - - - - security, Spring - - - - - - - - - - - © 2014 Baeldung. All Rights Reserved. - - - - - - - -
-
-
- -
- - Spring Security Digest Authentication - - - - - - Return to Content - - - - - - Contents - - - 1. Overview - - - 2. The Security XML Configuration - - - 3. Consuming the Secured Application - - - 4. The Maven Dependencies - - - 5. Conclusion - - - If you're new here, you may want to get my "REST APIs with Spring" eBook. Thanks for visiting! - - - -
- <anchor xml:id="dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> - This tutorial shows how to set up, configure and customize Digest Authentication with Spring. Similar to the previous article covering Basic Authentication, we’re going to built on top of the Spring MVC tutorial, and secure the application with the Digest Auth mechanism provided by Spring Security. -
- <anchor xml:id="dbdoclet.2_The_Security_XML_Configuration"/><emphasis role="bold">2. The Security XML Configuration</emphasis> - First thing to understand about the configuration is that, while Spring Security does have full out of the box support for the Digest authentication mechanism, this support is not as well integrated into the namespace as Basic Authentication was. - In this case, we need to manually define the raw beans that are going to make up the security configuration – the DigestAuthenticationFilter and the DigestAuthenticationEntryPoint: - <?xml version="1.0" encoding="UTF-8"?> -<beans:beans xmlns="http://www.springframework.org/schema/security" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:beans="http://www.springframework.org/schema/beans" - xsi:schemaLocation=" - http://www.springframework.org/schema/security - http://www.springframework.org/schema/security/spring-security-3.1.xsd - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> - -    <beans:bean id="digestFilter" - class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter"> -        <beans:property name="userDetailsService" ref="userService" /> -        <beans:property name="authenticationEntryPoint" ref="digestEntryPoint" /> -    </beans:bean> -    <beans:bean id="digestEntryPoint"  - class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint"> -        <beans:property name="realmName" value="Contacts Realm via Digest Authentication" /> -        <beans:property name="key" value="acegi" /> -    </beans:bean> - - <!-- the security namespace configuration --> - <http use-expressions="true" entry-point-ref="digestEntryPoint"> - <intercept-url pattern="/**" access="isAuthenticated()" /> - - <custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" /> - </http> - - <authentication-manager> - <authentication-provider> - <user-service id="userService"> - <user name="user1" password="user1Pass" authorities="ROLE_USER" /> - </user-service> - </authentication-provider> - </authentication-manager> - -</beans:beans> - Next, we need to integrate these beans into the overall security configuration – and in this case, the namespace is still flexible enough to allow us to do that. - The first part of this is pointing to the custom entry point bean, via the entry-point-ref attribute of the main <http> element. - The second part is adding the newly defined digest filter into the security filter chain. Since this filter is functionally equivalent to the BasicAuthenticationFilter, we are using the same relative position in the chain – this is specified by the BASIC_AUTH_FILTER alias in the overall Spring Security Standard Filters. - Finally, notice that the Digest Filter is configured to point to the user service bean – and here, the namespace is again very useful as it allows us to specify a bean name for the default user service created by the <user-service> element: - <user-service id="userService"> -
-
- <anchor xml:id="dbdoclet.3_Consuming_the_Secured_Application"/><emphasis role="bold">3. Consuming the Secured Application</emphasis> - We’re going to be using the curl command to consume the secured application and understand how a client can interact with it. - Let’s start by requesting the homepage – without providing security credentials in the request: - curl -i http://localhost/spring-security-mvc-digest-auth/homepage.html - As expected, we get back a response with a 401 Unauthorized status code: - HTTP/1.1 401 Unauthorized -Server: Apache-Coyote/1.1 -Set-Cookie: JSESSIONID=CF0233C...; Path=/spring-security-mvc-digest-auth/; HttpOnly -WWW-Authenticate: Digest realm="Contacts Realm via Digest Authentication", qop="auth", - nonce="MTM3MzYzODE2NTg3OTo3MmYxN2JkOWYxZTc4MzdmMzBiN2Q0YmY0ZTU0N2RkZg==" -Content-Type: text/html;charset=utf-8 -Content-Length: 1061 -Date: Fri, 12 Jul 2013 14:04:25 GMT - If this request were sent by the browser, the authentication challenge would prompt the user for credentials using a simple user/password dialog. - Let’s now provide the correct credentials and send the request again: - curl -i --digest --user - user1:user1Pass http://localhost/spring-security-mvc-digest-auth/homepage.html - Notice that we are enabling Digest Authentication for the curl command via the –digest flag. - The first response from the server will be the same – the 401 Unauthorized – but the challenge will now be interpreted and acted upon by a second request – which will succeed with a 200 OK: - HTTP/1.1 401 Unauthorized -Server: Apache-Coyote/1.1 -Set-Cookie: JSESSIONID=A961E0D...; Path=/spring-security-mvc-digest-auth/; HttpOnly -WWW-Authenticate: Digest realm="Contacts Realm via Digest Authentication", qop="auth", - nonce="MTM3MzYzODgyOTczMTo3YjM4OWQzMGU0YTgwZDg0YmYwZjRlZWJjMDQzZWZkOA==" -Content-Type: text/html;charset=utf-8 -Content-Length: 1061 -Date: Fri, 12 Jul 2013 14:15:29 GMT - -HTTP/1.1 200 OK -Server: Apache-Coyote/1.1 -Set-Cookie: JSESSIONID=55F996B...; Path=/spring-security-mvc-digest-auth/; HttpOnly -Content-Type: text/html;charset=ISO-8859-1 -Content-Language: en-US -Content-Length: 90 -Date: Fri, 12 Jul 2013 14:15:29 GMT - -<html> -<head></head> - -<body> - <h1>This is the homepage</h1> -</body> -</html> - A final note on this interaction is that a client can preemptively send the correct Authorization header with the first request, and thus entirely avoid the server security challenge and the second request. -
-
- <anchor xml:id="dbdoclet.4_The_Maven_Dependencies"/><emphasis role="bold">4. The Maven Dependencies</emphasis> - The security dependencies are discussed in depth in the Spring Security Maven tutorial. In short, we will need to define spring-security-web and spring-security-config as dependencies in our pom.xml. -
-
- <anchor xml:id="dbdoclet.5_Conclusion"/><emphasis role="bold">5. Conclusion</emphasis> - In this tutorial we introduce security into a simple Spring MVC project by leveraging the Digest Authentication support in the framework. - The implementation of these examples can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is. - When the project runs locally, the homepage html can be accessed at (or, with minimal Tomcat configuration, on port 80): - http://localhost:8080/spring-security-mvc-digest-auth/homepage.html - Finally, there is no reason an application needs to choose between Basic and Digest authentication – both can be set up simultaneously on the same URI structure, in such a way that the client can pick between the two mechanisms when consuming the web application. - - - - - - - - - - security, Spring - - - - - - - - - - - © 2014 Baeldung. All Rights Reserved. - - - - - - - -
-
-
- -
- - Basic and Digest Authentication for a REST Service with Spring Security - - - - - - Return to Content - - - - - - Contents - - - Table of Contents - - - 1. Overview - - - 2. Configuration of Basic Authentication - - - 3. Configuration of Digest Authentication - - - 4. Supporting both authentication protocols in the same RESTful service - - - 5. Testing both scenarios - - - 6. Conclusion - - - If you're new here, you may want to get my "REST APIs with Spring" eBook. Thanks for visiting! - - - -
- <anchor xml:id="Table_of_Contents"/><emphasis role="bold">Table of Contents</emphasis> - - - 1. Overview - - - 2. Configuration of Basic Authentication - - -     2.1. Satisfying the stateless constraint – getting rid of sessions - - - 3. Configuration of Digest Authentication - - - 4. Supporting both authentication protocols in the same RESTful service - - -     4.1. Anonymous request - - -     4.2. Request with authentication credentials - - - 5. Testing both scenarios - - - 6. Conclusion - - -
- <anchor xml:id="dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> - This article discusses how to set up both Basic and Digest Authentication on the same URI structure of a REST API. In a previous article, we discussed another method of securing the REST Service – form based authentication, so Basic and Digest authentication is the natural alternative, as well as the more RESTful one. -
-
- <anchor xml:id="dbdoclet.2_Configuration_of_Basic_Authentication"/><emphasis role="bold">2. Configuration of Basic Authentication</emphasis> - The main reason that form based authentication is not ideal for a RESTful Service is that Spring Security will make use of Sessions – this is of course state on the server, so the statelessness constraints in REST is practically ignored. - We’ll start by setting up Basic Authentication – first we remove the old custom entry point and filter from the main <http> security element: - <http create-session="stateless"> - <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" /> - - <http-basic /> -</http> - Note how support for basic authentication has been added with a single configuration line – <http-basic /> – which handles the creation and wiring of both the BasicAuthenticationFilter and the BasicAuthenticationEntryPoint. -
- <emphasis role="bold">2.1. Satisfying the stateless constraint – getting rid of sessions</emphasis> - One of the main constraints of the RESTful architectural style is that the client-server communication is fully stateless, as the original dissertation reads: -
-     5.1.3 Stateless - We next add a constraint to the client-server interaction: communication must be stateless in nature, as in the client-stateless-server (CSS) style of Section 3.4.3 (Figure 5-3), such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. -
- The concept of Session on the server is one with a long history in Spring Security, and removing it entirely has been difficult until now, especially when configuration was done by using the namespace. However, Spring Security 3.1 augments the namespace configuration with a new stateless option for session creation, which effectively guarantees that no session will be created or used by Spring. What this new option does is completely removes all session related filters from the security filter chain, ensuring that authentication is performed for each request. -
-
-
- <anchor xml:id="dbdoclet.3_Configuration_of_Digest_Authentication"/><emphasis role="bold">3. Configuration of Digest Authentication</emphasis> - Starting with the previous configuration, the filter and entry point necessary to set up digest authentication will be defined as beans. Then, the digest entry point will override the one created by <http-basic> behind the scenes. Finally, the custom digest filter will be introduced in the security filter chain using the after semantics of the security namespace to position it directly after the basic authentication filter. - <http create-session="stateless" entry-point-ref="digestEntryPoint"> - <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" /> - - <http-basic /> - <custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" /> -</http> - -<beans:bean id="digestFilter" class= - "org.springframework.security.web.authentication.www.DigestAuthenticationFilter"> - <beans:property name="userDetailsService" ref="userService" /> - <beans:property name="authenticationEntryPoint" ref="digestEntryPoint" /> -</beans:bean> - -<beans:bean id="digestEntryPoint" class= - "org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint"> - <beans:property name="realmName" value="Contacts Realm via Digest Authentication"/> - <beans:property name="key" value="acegi" /> -</beans:bean> - -<authentication-manager> - <authentication-provider> - <user-service id="userService"> - <user name="eparaschiv" password="eparaschiv" authorities="ROLE_ADMIN" /> - <user name="user" password="user" authorities="ROLE_USER" /> - </user-service> - </authentication-provider> -</authentication-manager> - Unfortunately there is no support in the security namespace to automatically configure the digest authentication the way basic authentication can be configured with <http-basic>. Because of that, the necessary beans had to be defined and wired manually into the security configuration. -
-
- <anchor xml:id="dbdoclet.4_Supporting_both_authentication_protocols_in_the_same_RESTful_service"/><emphasis role="bold">4. Supporting both authentication protocols in the same RESTful service</emphasis> - Basic or Digest authentication alone can be easily implemented in Spring Security 3.x; it is supporting both of them for the same RESTful web service, on the same URI mappings that introduces a new level of complexity into the configuration and testing of the service. -
- <emphasis role="bold">4.1. Anonymous request</emphasis> - With both basic and digest filters in the security chain, the way a anonymous request – a request containing no authentication credentials (Authorization HTTP header) – is processed by Spring Security is – the two authentication filters will find no credentials and will continue execution of the filter chain. Then, seeing how the request wasn’t authenticated, an AccessDeniedException is thrown and caught in the ExceptionTranslationFilter, which commences the digest entry point, prompting the client for credentials. - The responsibilities of both the basic and digest filters are very narrow – they will continue to execute the security filter chain if they are unable to identify the type of authentication credentials in the request. It is because of this that Spring Security can have the flexibility to be configured with support for multiple authentication protocols on the same URI. - When a request is made containing the correct authentication credentials – either basic or digest – that protocol will be rightly used. However, for an anonymous request, the client will get prompted only for digest authentication credentials. This is because the digest entry point is configured as the main and single entry point of the Spring Security chain; as such digest authentication can be considered the default. -
-
- <emphasis role="bold">4.2. Request with authentication credentials</emphasis> - A request with credentials for Basic authentication will be identified by the Authorization header starting with the prefix “Basic”. When processing such a request, the credentials will be decoded in the basic authentication filter and the request will be authorized. Similarly, a request with credentials for Digest authentication will use the prefix “Digest”  for it’s Authorization header. -
-
-
- <anchor xml:id="dbdoclet.5_Testing_both_scenarios"/><emphasis role="bold">5. Testing both scenarios</emphasis> - The tests will consume the REST service by creating a new resource after authenticating with either basic or digest: - @Test -public void givenAuthenticatedByBasicAuth_whenAResourceIsCreated_then201IsReceived(){ - // Given - // When - Response response = given() - .auth().preemptive().basic( ADMIN_USERNAME, ADMIN_PASSWORD ) - .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) ) - .post( paths.getFooURL() ); - - // Then - assertThat( response.getStatusCode(), is( 201 ) ); -} -@Test -public void givenAuthenticatedByDigestAuth_whenAResourceIsCreated_then201IsReceived(){ - // Given - // When - Response response = given() - .auth().digest( ADMIN_USERNAME, ADMIN_PASSWORD ) - .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) ) - .post( paths.getFooURL() ); - - // Then - assertThat( response.getStatusCode(), is( 201 ) ); -} - Note that the test using basic authentication adds credentials to the request preemptively, regardless if the server has challenged for authentication or not. This is to ensure that the server doesn’t need to challenge the client for credentials, because if it did, the challenge would be for Digest credentials, since that is the default. -
-
- <anchor xml:id="dbdoclet.6_Conclusion"/><emphasis role="bold">6. Conclusion</emphasis> - This article covered the configuration and implementation of both Basic and Digest authentication for a RESTful service, using mostly Spring Security 3.0 namespace support as well as some new features added by Spring Security 3.1. - For the full implementation, check out the github project. - - - - - - - - - - REST, security, Spring - - - - - - - - - - - © 2014 Baeldung. All Rights Reserved. - - - - - - - -
-
-
diff --git a/apache-fop/src/test/resources/output_herold.pdf b/apache-fop/src/test/resources/output_herold.pdf deleted file mode 100644 index 1d23de7b61..0000000000 Binary files a/apache-fop/src/test/resources/output_herold.pdf and /dev/null differ diff --git a/apache-fop/src/test/resources/output_html2fo.pdf b/apache-fop/src/test/resources/output_html2fo.pdf deleted file mode 100644 index 7c2b4a0c51..0000000000 Binary files a/apache-fop/src/test/resources/output_html2fo.pdf and /dev/null differ diff --git a/apache-fop/src/test/resources/output_jtidy.pdf b/apache-fop/src/test/resources/output_jtidy.pdf deleted file mode 100644 index 1d9456122c..0000000000 Binary files a/apache-fop/src/test/resources/output_jtidy.pdf and /dev/null differ diff --git a/apache-geode/pom.xml b/apache-geode/pom.xml index 15c7e04d29..195dfadd20 100644 --- a/apache-geode/pom.xml +++ b/apache-geode/pom.xml @@ -19,25 +19,7 @@ geode-core ${geode.core}
- - junit - junit - ${junit.version} -
- - - - - org.apache.maven.plugins - maven-compiler-plugin - - ${java.version} - ${java.version} - - - - 1.6.0 diff --git a/apache-meecrowave/pom.xml b/apache-meecrowave/pom.xml index 4eb1094f94..51c6514992 100644 --- a/apache-meecrowave/pom.xml +++ b/apache-meecrowave/pom.xml @@ -1,7 +1,6 @@ 4.0.0 - com.baeldung apache-meecrowave 0.0.1 apache-meecrowave @@ -38,13 +37,6 @@ ${meecrowave-junit.version} test
- - - junit - junit - ${junit.version} - test - diff --git a/apache-olingo/olingo2/pom.xml b/apache-olingo/olingo2/pom.xml index 727e6ca484..95b123efbc 100644 --- a/apache-olingo/olingo2/pom.xml +++ b/apache-olingo/olingo2/pom.xml @@ -5,7 +5,6 @@ 4.0.0 org.baeldung.examples.olingo2 olingo2 - 0.0.1-SNAPSHOT olingo2 Sample Olingo 2 Project diff --git a/apache-pulsar/pom.xml b/apache-pulsar/pom.xml index 8a0882dae1..fdd9ae1e95 100644 --- a/apache-pulsar/pom.xml +++ b/apache-pulsar/pom.xml @@ -24,8 +24,6 @@ - 1.8 - 1.8 - 2.1.1-incubating + 2.1.1-incubating diff --git a/apache-shiro/README.md b/apache-shiro/README.md index 553eeecc69..ed63c569da 100644 --- a/apache-shiro/README.md +++ b/apache-shiro/README.md @@ -4,4 +4,6 @@ This module contains articles about Apache Shiro ### Relevant articles: -- [Introduction to Apache Shiro](https://www.baeldung.com/apache-shiro) \ No newline at end of file +- [Introduction to Apache Shiro](https://www.baeldung.com/apache-shiro) +- [Permissions-Based Access Control with Apache Shiro](https://www.baeldung.com/apache-shiro-access-control) + diff --git a/apache-solrj/pom.xml b/apache-solrj/pom.xml index 1227fdca46..b19ceb1e48 100644 --- a/apache-solrj/pom.xml +++ b/apache-solrj/pom.xml @@ -1,7 +1,6 @@ 4.0.0 - com.baeldung apache-solrj 0.0.1-SNAPSHOT apache-solrj diff --git a/apache-spark/README.md b/apache-spark/README.md index 360a18f095..52313d66bf 100644 --- a/apache-spark/README.md +++ b/apache-spark/README.md @@ -6,3 +6,5 @@ This module contains articles about Apache Spark - [Introduction to Apache Spark](https://www.baeldung.com/apache-spark) - [Building a Data Pipeline with Kafka, Spark Streaming and Cassandra](https://www.baeldung.com/kafka-spark-data-pipeline) +- [Machine Learning with Spark MLlib](https://www.baeldung.com/spark-mlib-machine-learning) + diff --git a/apache-spark/pom.xml b/apache-spark/pom.xml index 3df81e5aee..41fd51d9fd 100644 --- a/apache-spark/pom.xml +++ b/apache-spark/pom.xml @@ -2,7 +2,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.baeldung apache-spark 1.0-SNAPSHOT apache-spark @@ -59,15 +58,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${java.version} - ${java.version} - - maven-assembly-plugin @@ -95,7 +85,6 @@ 2.3.0 2.3.0 1.5.2 - 3.2 diff --git a/apache-tapestry/pom.xml b/apache-tapestry/pom.xml new file mode 100644 index 0000000000..da033d69d5 --- /dev/null +++ b/apache-tapestry/pom.xml @@ -0,0 +1,147 @@ + + 4.0.0 + com.baeldung + apache-tapestry + 0.0.1-SNAPSHOT + war + apache-tapestry + + + + org.apache.tapestry + tapestry-core + ${tapestry-release-version} + + + + + org.slf4j + slf4j-log4j12 + ${slf4j-release-version} + + + + org.apache.tapestry + tapestry-webresources + ${tapestry-release-version} + + + + + + + + org.testng + testng + ${testng-release-version} + test + + + + org.apache.tapestry + tapestry-test + ${tapestry-release-version} + test + + + + + javax.servlet + servlet-api + ${servlet-api-release-version} + provided + + + + + org.apache.tapestry + tapestry-javadoc + ${tapestry-release-version} + provided + + + + + apache-tapestry + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.7.2 + + + Qa + + + + + + + org.mortbay.jetty + maven-jetty-plugin + 6.1.16 + + + + + true + + + + tapestry.execution-mode + development + + + + + + + + + + + + jboss + http://repository.jboss.org/nexus/content/groups/public/ + + + + + apache-staging + https://repository.apache.org/content/groups/staging/ + + + + + 5.4.5 + 2.5 + 6.8.21 + 1.7.19 + + + diff --git a/apache-tapestry/src/main/java/com/baeldung/tapestry/components/Layout.java b/apache-tapestry/src/main/java/com/baeldung/tapestry/components/Layout.java new file mode 100644 index 0000000000..5316bd9722 --- /dev/null +++ b/apache-tapestry/src/main/java/com/baeldung/tapestry/components/Layout.java @@ -0,0 +1,16 @@ +package com.baeldung.tapestry.components; + +import org.apache.tapestry5.BindingConstants; +import org.apache.tapestry5.annotations.Parameter; +import org.apache.tapestry5.annotations.Property; + +/** + * Layout component for pages of application. + */ +public class Layout { + + @Property + @Parameter(required = true, defaultPrefix = BindingConstants.LITERAL) + private String title; + +} diff --git a/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Error404.java b/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Error404.java new file mode 100644 index 0000000000..c629b82d01 --- /dev/null +++ b/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Error404.java @@ -0,0 +1,5 @@ +package com.baeldung.tapestry.pages; + +public class Error404 { + +} diff --git a/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Home.java b/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Home.java new file mode 100644 index 0000000000..34e99a9cce --- /dev/null +++ b/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Home.java @@ -0,0 +1,36 @@ +package com.baeldung.tapestry.pages; + +import java.util.Date; + +import org.apache.tapestry5.Block; +import org.apache.tapestry5.annotations.Log; +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.ioc.annotations.Inject; +import org.apache.tapestry5.services.ajax.AjaxResponseRenderer; +import org.slf4j.Logger; + +public class Home { + + @Property + private String appName = "apache-tapestry"; + + public Date getCurrentTime() { + return new Date(); + } + + @Inject + private Logger logger; + + @Inject + private AjaxResponseRenderer ajaxResponseRenderer; + + @Inject + private Block ajaxBlock; + + @Log + void onCallAjax() { + logger.info("Ajax call"); + ajaxResponseRenderer.addRender("ajaxZone", ajaxBlock); + } + +} diff --git a/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Index.java b/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Index.java new file mode 100644 index 0000000000..7d9e9a1aaa --- /dev/null +++ b/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Index.java @@ -0,0 +1,59 @@ +package com.baeldung.tapestry.pages; + + +import org.apache.tapestry5.Block; +import org.apache.tapestry5.EventContext; +import org.apache.tapestry5.SymbolConstants; +import org.apache.tapestry5.annotations.InjectPage; +import org.apache.tapestry5.annotations.Log; +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.ioc.annotations.Inject; +import org.apache.tapestry5.ioc.annotations.Symbol; +import org.apache.tapestry5.services.HttpError; +import org.apache.tapestry5.services.ajax.AjaxResponseRenderer; +import org.slf4j.Logger; + +import java.util.Date; + +/** + * Start page of application apache-tapestry. + */ +public class Index { + @Inject + private Logger logger; + + @Inject + private AjaxResponseRenderer ajaxResponseRenderer; + + @Property + @Inject + @Symbol(SymbolConstants.TAPESTRY_VERSION) + private String tapestryVersion; + + @Inject + private Block block; + + // Handle call with an unwanted context + Object onActivate(EventContext eventContext) { + return eventContext.getCount() > 0 ? + new HttpError(404, "Resource not found") : + null; + } + + @Log + void onComplete() { + logger.info("Complete call on Index page"); + } + + @Log + void onAjax() { + logger.info("Ajax call on Index page"); + + ajaxResponseRenderer.addRender("middlezone", block); + } + + public Date getCurrentTime() { + return new Date(); + } + +} diff --git a/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Login.java b/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Login.java new file mode 100644 index 0000000000..c5005f11f5 --- /dev/null +++ b/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Login.java @@ -0,0 +1,42 @@ +package com.baeldung.tapestry.pages; + +import org.apache.tapestry5.alerts.AlertManager; +import org.apache.tapestry5.annotations.InjectComponent; +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.corelib.components.Form; +import org.apache.tapestry5.ioc.annotations.Inject; +import org.slf4j.Logger; + +public class Login { + @Inject + private Logger logger; + + @Inject + private AlertManager alertManager; + + @InjectComponent + private Form login; + + @Property + private String email; + + @Property + private String password; + + void onValidateFromLogin() { + if(email == null || password == null) { + alertManager.error("Email/Password is null"); + login.recordError("Validation failed"); + } + } + + Object onSuccessFromLogin() { + alertManager.success("Welcome! Login Successful"); + return Home.class; + } + + void onFailureFromLogin() { + alertManager.error("Please try again with correct credentials"); + } + +} diff --git a/apache-tapestry/src/main/java/com/baeldung/tapestry/services/AppModule.java b/apache-tapestry/src/main/java/com/baeldung/tapestry/services/AppModule.java new file mode 100644 index 0000000000..c4d57d5b86 --- /dev/null +++ b/apache-tapestry/src/main/java/com/baeldung/tapestry/services/AppModule.java @@ -0,0 +1,128 @@ +package com.baeldung.tapestry.services; + +import java.io.IOException; + +import org.apache.tapestry5.SymbolConstants; +import org.apache.tapestry5.ioc.MappedConfiguration; +import org.apache.tapestry5.ioc.OrderedConfiguration; +import org.apache.tapestry5.ioc.ServiceBinder; +import org.apache.tapestry5.ioc.annotations.Contribute; +import org.apache.tapestry5.ioc.annotations.Local; +import org.apache.tapestry5.ioc.services.ApplicationDefaults; +import org.apache.tapestry5.ioc.services.SymbolProvider; +import org.apache.tapestry5.services.Request; +import org.apache.tapestry5.services.RequestFilter; +import org.apache.tapestry5.services.RequestHandler; +import org.apache.tapestry5.services.Response; +import org.slf4j.Logger; + +/** + * This module is automatically included as part of the Tapestry IoC Registry, it's a good place to + * configure and extend Tapestry, or to place your own service definitions. + */ +public class AppModule { + public static void bind(ServiceBinder binder) { + // binder.bind(MyServiceInterface.class, MyServiceImpl.class); + + // Make bind() calls on the binder object to define most IoC services. + // Use service builder methods (example below) when the implementation + // is provided inline, or requires more initialization than simply + // invoking the constructor. + } + + public static void contributeFactoryDefaults( + MappedConfiguration configuration) { + // The values defined here (as factory default overrides) are themselves + // overridden with application defaults by DevelopmentModule and QaModule. + + // The application version is primarily useful as it appears in + // any exception reports (HTML or textual). + configuration.override(SymbolConstants.APPLICATION_VERSION, "0.0.1-SNAPSHOT"); + + // This is something that should be removed when going to production, but is useful + // in the early stages of development. + configuration.override(SymbolConstants.PRODUCTION_MODE, false); + } + + public static void contributeApplicationDefaults( + MappedConfiguration configuration) { + // Contributions to ApplicationDefaults will override any contributions to + // FactoryDefaults (with the same key). Here we're restricting the supported + // locales to just "en" (English). As you add localised message catalogs and other assets, + // you can extend this list of locales (it's a comma separated series of locale names; + // the first locale name is the default when there's no reasonable match). + configuration.add(SymbolConstants.SUPPORTED_LOCALES, "en"); + + // You should change the passphrase immediately; the HMAC passphrase is used to secure + // the hidden field data stored in forms to encrypt and digitally sign client-side data. + configuration.add(SymbolConstants.HMAC_PASSPHRASE, "change this immediately"); + } + + /** + * Use annotation or method naming convention: contributeApplicationDefaults + */ + @Contribute(SymbolProvider.class) + @ApplicationDefaults + public static void setupEnvironment(MappedConfiguration configuration) { + // Support for jQuery is new in Tapestry 5.4 and will become the only supported + // option in 5.5. + configuration.add(SymbolConstants.JAVASCRIPT_INFRASTRUCTURE_PROVIDER, "jquery"); + configuration.add(SymbolConstants.BOOTSTRAP_ROOT, "context:mybootstrap"); + } + + + /** + * This is a service definition, the service will be named "TimingFilter". The interface, + * RequestFilter, is used within the RequestHandler service pipeline, which is built from the + * RequestHandler service configuration. Tapestry IoC is responsible for passing in an + * appropriate Logger instance. Requests for static resources are handled at a higher level, so + * this filter will only be invoked for Tapestry related requests. + * + * + * Service builder methods are useful when the implementation is inline as an inner class + * (as here) or require some other kind of special initialization. In most cases, + * use the static bind() method instead. + * + * + * If this method was named "build", then the service id would be taken from the + * service interface and would be "RequestFilter". Since Tapestry already defines + * a service named "RequestFilter" we use an explicit service id that we can reference + * inside the contribution method. + */ + public RequestFilter buildTimingFilter(final Logger log) { + return new RequestFilter() { + public boolean service(Request request, Response response, RequestHandler handler) + throws IOException { + long startTime = System.currentTimeMillis(); + + try { + // The responsibility of a filter is to invoke the corresponding method + // in the handler. When you chain multiple filters together, each filter + // received a handler that is a bridge to the next filter. + + return handler.service(request, response); + } finally { + long elapsed = System.currentTimeMillis() - startTime; + + log.info("Request time: {} ms", elapsed); + } + } + }; + } + + /** + * This is a contribution to the RequestHandler service configuration. This is how we extend + * Tapestry using the timing filter. A common use for this kind of filter is transaction + * management or security. The @Local annotation selects the desired service by type, but only + * from the same module. Without @Local, there would be an error due to the other service(s) + * that implement RequestFilter (defined in other modules). + */ + @Contribute(RequestHandler.class) + public void addTimingFilter(OrderedConfiguration configuration, @Local RequestFilter filter) { + // Each contribution to an ordered configuration has a name, When necessary, you may + // set constraints to precisely control the invocation order of the contributed filter + // within the pipeline. + + configuration.add("Timing", filter); + } +} diff --git a/apache-tapestry/src/main/java/com/baeldung/tapestry/services/DevelopmentModule.java b/apache-tapestry/src/main/java/com/baeldung/tapestry/services/DevelopmentModule.java new file mode 100644 index 0000000000..d9c8493e39 --- /dev/null +++ b/apache-tapestry/src/main/java/com/baeldung/tapestry/services/DevelopmentModule.java @@ -0,0 +1,24 @@ +package com.baeldung.tapestry.services; + +import org.apache.tapestry5.SymbolConstants; +import org.apache.tapestry5.ioc.MappedConfiguration; + +/** + * This module is automatically included as part of the Tapestry IoC Registry if tapestry.execution-mode + * includes development. + */ +public class DevelopmentModule { + public static void contributeApplicationDefaults( + MappedConfiguration configuration) { + // The factory default is true but during the early stages of an application + // overriding to false is a good idea. In addition, this is often overridden + // on the command line as -Dtapestry.production-mode=false + configuration.add(SymbolConstants.PRODUCTION_MODE, false); + + // The application version number is incorprated into URLs for some + // assets. Web browsers will cache assets because of the far future expires + // header. If existing assets are changed, the version number should also + // change, to force the browser to download new versions. + configuration.add(SymbolConstants.APPLICATION_VERSION, "0.0.1-SNAPSHOT-DEV"); + } +} diff --git a/apache-tapestry/src/main/java/com/baeldung/tapestry/services/QaModule.java b/apache-tapestry/src/main/java/com/baeldung/tapestry/services/QaModule.java new file mode 100644 index 0000000000..fc6fb595e9 --- /dev/null +++ b/apache-tapestry/src/main/java/com/baeldung/tapestry/services/QaModule.java @@ -0,0 +1,34 @@ +package com.baeldung.tapestry.services; + +import org.apache.tapestry5.SymbolConstants; +import org.apache.tapestry5.ioc.MappedConfiguration; +import org.apache.tapestry5.ioc.ServiceBinder; + +/** + * This module is automatically included as part of the Tapestry IoC Registry if tapestry.execution-mode + * includes qa ("quality assurance"). + */ +public class QaModule +{ + public static void bind(ServiceBinder binder) + { + // Bind any services needed by the QA team to produce their reports + // binder.bind(MyServiceMonitorInterface.class, MyServiceMonitorImpl.class); + } + + + public static void contributeApplicationDefaults( + MappedConfiguration configuration) + { + // The factory default is true but during the early stages of an application + // overriding to false is a good idea. In addition, this is often overridden + // on the command line as -Dtapestry.production-mode=false + configuration.add(SymbolConstants.PRODUCTION_MODE, false); + + // The application version number is incorprated into URLs for some + // assets. Web browsers will cache assets because of the far future expires + // header. If existing assets are changed, the version number should also + // change, to force the browser to download new versions. + configuration.add(SymbolConstants.APPLICATION_VERSION, "0.0.1-SNAPSHOT-QA"); + } +} diff --git a/apache-tapestry/src/main/resources/com/baeldung/tapestry/components/Layout.tml b/apache-tapestry/src/main/resources/com/baeldung/tapestry/components/Layout.tml new file mode 100644 index 0000000000..baa17aef8e --- /dev/null +++ b/apache-tapestry/src/main/resources/com/baeldung/tapestry/components/Layout.tml @@ -0,0 +1,21 @@ + + + ${title} + + +
+
+
+ +
+
+
+
+ +
+
+

© Your Company

+
+
+ + diff --git a/apache-tapestry/src/main/resources/com/baeldung/tapestry/logback.xml b/apache-tapestry/src/main/resources/com/baeldung/tapestry/logback.xml new file mode 100644 index 0000000000..2997ecb099 --- /dev/null +++ b/apache-tapestry/src/main/resources/com/baeldung/tapestry/logback.xml @@ -0,0 +1,13 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + diff --git a/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Error404.tml b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Error404.tml new file mode 100644 index 0000000000..b18492221e --- /dev/null +++ b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Error404.tml @@ -0,0 +1,11 @@ + + +
+
+

Requested page not found!

+
+
+ + diff --git a/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.properties b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.properties new file mode 100644 index 0000000000..4647845163 --- /dev/null +++ b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.properties @@ -0,0 +1 @@ +introMsg=Welcome to the Apache Tapestry Tutorial diff --git a/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.tml b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.tml new file mode 100644 index 0000000000..3dafb63f0a --- /dev/null +++ b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.tml @@ -0,0 +1,14 @@ + + +

Home! ${appName}

+

${message:introMsg}

+

${currentTime}

+

Call Ajax

+ + +
+

Rendered through Ajax

+

The current time is: ${currentTime}

+
+ + diff --git a/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.properties b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.properties new file mode 100644 index 0000000000..bc49edd53f --- /dev/null +++ b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.properties @@ -0,0 +1 @@ +greeting=Welcome to Tapestry 5! We hope that this project template will get you going in style. diff --git a/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.tml b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.tml new file mode 100644 index 0000000000..625a3c2fcc --- /dev/null +++ b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.tml @@ -0,0 +1,46 @@ + + + + + +
+

+ ${message:greeting} +

+

${message:greeting}

+

The current time is: ${currentTime}

+

+ This is a template for a simple marketing or informational website. It includes a large callout called + the hero unit and three supporting pieces of content. Use it as a starting point to create something + more unique. +

+

Learn more »

+
+ + +
+
+

Normal link

+

Clink the bottom link and the page refresh with event complete

+

Complete»

+
+ + + +
+

Ajax link

+

Click the bottom link to update just the middle column with Ajax call with event ajax

+

Ajax»

+
+
+ + +

Ajax updated

+

I'v been updated through AJAX call

+

The current time is: ${currentTime}

+
+ + diff --git a/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Login.tml b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Login.tml new file mode 100644 index 0000000000..ac78a55341 --- /dev/null +++ b/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Login.tml @@ -0,0 +1,16 @@ + + +
+
+ +

Please sign in

+ + + +
+
+
+ + diff --git a/apache-tapestry/src/main/resources/log4j.properties b/apache-tapestry/src/main/resources/log4j.properties new file mode 100644 index 0000000000..bd90a762ca --- /dev/null +++ b/apache-tapestry/src/main/resources/log4j.properties @@ -0,0 +1,44 @@ +# Default to info level output; this is very handy if you eventually use Hibernate as well. +log4j.rootCategory=info, A1 + +# A1 is set to be a ConsoleAppender. +log4j.appender.A1=org.apache.log4j.ConsoleAppender + +# A1 uses PatternLayout. +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +log4j.appender.A1.layout.ConversionPattern=[%p] %c{2} %m%n + +# Service category names are the name of the defining module class +# and then the service id. +log4j.category.com.baeldung.tapestry.services.AppModule.TimingFilter=info + +# Outputs a list of pages, components and mixins at startup. +log4j.category.org.apache.tapestry5.modules.TapestryModule.ComponentClassResolver=info + +# Outputs startup statistics; elapsed time to setup and initialize the registry, a list of +# available services, and a launch banner that includes the Tapestry version number. +log4j.category.org.apache.tapestry5.TapestryFilter=info + + +# Turning on debug mode for a page's or component's transformer logger +# will show all of the code changes that occur when the +# class is loaded. + +# log4j.category.tapestry.transformer.com.baeldung.tapestry.pages.Index=debug + +# Turning on debug mode for a component's events logger will show all the events triggered on the +# component, and which component methods are invoked as a result. + +# log4j.category.tapestry.events.com.baeldung.tapestry.pages.Index=debug + +# Turning on trace mode for a page's render logger provides extended information about every step +# in rendering (this is not generally helpful). Turning on debug mode will add a one-line +# summary that includes the elapsed render time, which can be useful in tracking down +# performance issues. + +# log4j.category.tapestry.render.com.baeldung.tapestry.pages.Index=debug + +# Turn on some verbose debugging about everything in the application. This is nice initially, +# while getting everything set up. You'll probably want to remove this once you are +# up and running, replacing it with more selective debugging output. +log4j.category.com.baeldung.tapestry=debug diff --git a/apache-tapestry/src/main/webapp/WEB-INF/app.properties b/apache-tapestry/src/main/webapp/WEB-INF/app.properties new file mode 100644 index 0000000000..1c299311bb --- /dev/null +++ b/apache-tapestry/src/main/webapp/WEB-INF/app.properties @@ -0,0 +1,4 @@ +# This is where global application properties go. +# You can also have individual message catalogs for each page and each +# component that override these defaults. +# The name of this file is based on the element in web. \ No newline at end of file diff --git a/apache-tapestry/src/main/webapp/WEB-INF/web.xml b/apache-tapestry/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..c5bdfd415c --- /dev/null +++ b/apache-tapestry/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,54 @@ + + + + + apache-tapestry Tapestry 5 Application + + + tapestry.app-package + com.baeldung.tapestry + + + + + tapestry.development-modules + + com.baeldung.tapestry.services.DevelopmentModule + + + + tapestry.qa-modules + + com.baeldung.tapestry.services.QaModule + + + + + + + app + org.apache.tapestry5.TapestryFilter + + + + app + /* + REQUEST + ERROR + + + + 404 + /error404 + + + \ No newline at end of file diff --git a/apache-tapestry/src/main/webapp/favicon.ico b/apache-tapestry/src/main/webapp/favicon.ico new file mode 100644 index 0000000000..b9715a2aed Binary files /dev/null and b/apache-tapestry/src/main/webapp/favicon.ico differ diff --git a/apache-tapestry/src/main/webapp/images/tapestry.png b/apache-tapestry/src/main/webapp/images/tapestry.png new file mode 100644 index 0000000000..eba58883c6 Binary files /dev/null and b/apache-tapestry/src/main/webapp/images/tapestry.png differ diff --git a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/dist/css/bootstrap-theme.css b/apache-tapestry/src/main/webapp/mybootstrap/css/bootstrap-theme.css similarity index 84% rename from jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/dist/css/bootstrap-theme.css rename to apache-tapestry/src/main/webapp/mybootstrap/css/bootstrap-theme.css index 31d8882661..374a7e314a 100644 --- a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/dist/css/bootstrap-theme.css +++ b/apache-tapestry/src/main/webapp/mybootstrap/css/bootstrap-theme.css @@ -1,8 +1,9 @@ /*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ + .btn-default, .btn-primary, .btn-success, @@ -28,27 +29,6 @@ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); } -.btn-default.disabled, -.btn-primary.disabled, -.btn-success.disabled, -.btn-info.disabled, -.btn-warning.disabled, -.btn-danger.disabled, -.btn-default[disabled], -.btn-primary[disabled], -.btn-success[disabled], -.btn-info[disabled], -.btn-warning[disabled], -.btn-danger[disabled], -fieldset[disabled] .btn-default, -fieldset[disabled] .btn-primary, -fieldset[disabled] .btn-success, -fieldset[disabled] .btn-info, -fieldset[disabled] .btn-warning, -fieldset[disabled] .btn-danger { - -webkit-box-shadow: none; - box-shadow: none; -} .btn-default .badge, .btn-primary .badge, .btn-success .badge, @@ -84,23 +64,8 @@ fieldset[disabled] .btn-danger { border-color: #dbdbdb; } .btn-default.disabled, -.btn-default[disabled], -fieldset[disabled] .btn-default, -.btn-default.disabled:hover, -.btn-default[disabled]:hover, -fieldset[disabled] .btn-default:hover, -.btn-default.disabled:focus, -.btn-default[disabled]:focus, -fieldset[disabled] .btn-default:focus, -.btn-default.disabled.focus, -.btn-default[disabled].focus, -fieldset[disabled] .btn-default.focus, -.btn-default.disabled:active, -.btn-default[disabled]:active, -fieldset[disabled] .btn-default:active, -.btn-default.disabled.active, -.btn-default[disabled].active, -fieldset[disabled] .btn-default.active { +.btn-default:disabled, +.btn-default[disabled] { background-color: #e0e0e0; background-image: none; } @@ -125,23 +90,8 @@ fieldset[disabled] .btn-default.active { border-color: #245580; } .btn-primary.disabled, -.btn-primary[disabled], -fieldset[disabled] .btn-primary, -.btn-primary.disabled:hover, -.btn-primary[disabled]:hover, -fieldset[disabled] .btn-primary:hover, -.btn-primary.disabled:focus, -.btn-primary[disabled]:focus, -fieldset[disabled] .btn-primary:focus, -.btn-primary.disabled.focus, -.btn-primary[disabled].focus, -fieldset[disabled] .btn-primary.focus, -.btn-primary.disabled:active, -.btn-primary[disabled]:active, -fieldset[disabled] .btn-primary:active, -.btn-primary.disabled.active, -.btn-primary[disabled].active, -fieldset[disabled] .btn-primary.active { +.btn-primary:disabled, +.btn-primary[disabled] { background-color: #265a88; background-image: none; } @@ -166,23 +116,8 @@ fieldset[disabled] .btn-primary.active { border-color: #3e8f3e; } .btn-success.disabled, -.btn-success[disabled], -fieldset[disabled] .btn-success, -.btn-success.disabled:hover, -.btn-success[disabled]:hover, -fieldset[disabled] .btn-success:hover, -.btn-success.disabled:focus, -.btn-success[disabled]:focus, -fieldset[disabled] .btn-success:focus, -.btn-success.disabled.focus, -.btn-success[disabled].focus, -fieldset[disabled] .btn-success.focus, -.btn-success.disabled:active, -.btn-success[disabled]:active, -fieldset[disabled] .btn-success:active, -.btn-success.disabled.active, -.btn-success[disabled].active, -fieldset[disabled] .btn-success.active { +.btn-success:disabled, +.btn-success[disabled] { background-color: #419641; background-image: none; } @@ -207,23 +142,8 @@ fieldset[disabled] .btn-success.active { border-color: #28a4c9; } .btn-info.disabled, -.btn-info[disabled], -fieldset[disabled] .btn-info, -.btn-info.disabled:hover, -.btn-info[disabled]:hover, -fieldset[disabled] .btn-info:hover, -.btn-info.disabled:focus, -.btn-info[disabled]:focus, -fieldset[disabled] .btn-info:focus, -.btn-info.disabled.focus, -.btn-info[disabled].focus, -fieldset[disabled] .btn-info.focus, -.btn-info.disabled:active, -.btn-info[disabled]:active, -fieldset[disabled] .btn-info:active, -.btn-info.disabled.active, -.btn-info[disabled].active, -fieldset[disabled] .btn-info.active { +.btn-info:disabled, +.btn-info[disabled] { background-color: #2aabd2; background-image: none; } @@ -248,23 +168,8 @@ fieldset[disabled] .btn-info.active { border-color: #e38d13; } .btn-warning.disabled, -.btn-warning[disabled], -fieldset[disabled] .btn-warning, -.btn-warning.disabled:hover, -.btn-warning[disabled]:hover, -fieldset[disabled] .btn-warning:hover, -.btn-warning.disabled:focus, -.btn-warning[disabled]:focus, -fieldset[disabled] .btn-warning:focus, -.btn-warning.disabled.focus, -.btn-warning[disabled].focus, -fieldset[disabled] .btn-warning.focus, -.btn-warning.disabled:active, -.btn-warning[disabled]:active, -fieldset[disabled] .btn-warning:active, -.btn-warning.disabled.active, -.btn-warning[disabled].active, -fieldset[disabled] .btn-warning.active { +.btn-warning:disabled, +.btn-warning[disabled] { background-color: #eb9316; background-image: none; } @@ -289,23 +194,8 @@ fieldset[disabled] .btn-warning.active { border-color: #b92c28; } .btn-danger.disabled, -.btn-danger[disabled], -fieldset[disabled] .btn-danger, -.btn-danger.disabled:hover, -.btn-danger[disabled]:hover, -fieldset[disabled] .btn-danger:hover, -.btn-danger.disabled:focus, -.btn-danger[disabled]:focus, -fieldset[disabled] .btn-danger:focus, -.btn-danger.disabled.focus, -.btn-danger[disabled].focus, -fieldset[disabled] .btn-danger.focus, -.btn-danger.disabled:active, -.btn-danger[disabled]:active, -fieldset[disabled] .btn-danger:active, -.btn-danger.disabled.active, -.btn-danger[disabled].active, -fieldset[disabled] .btn-danger.active { +.btn-danger:disabled, +.btn-danger[disabled] { background-color: #c12e2a; background-image: none; } @@ -370,7 +260,6 @@ fieldset[disabled] .btn-danger.active { filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); background-repeat: repeat-x; - border-radius: 4px; } .navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .active > a { @@ -584,4 +473,4 @@ fieldset[disabled] .btn-danger.active { -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); } -/*# sourceMappingURL=bootstrap-theme.css.map */ + diff --git a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/dist/css/bootstrap.css b/apache-tapestry/src/main/webapp/mybootstrap/css/bootstrap.css similarity index 94% rename from jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/dist/css/bootstrap.css rename to apache-tapestry/src/main/webapp/mybootstrap/css/bootstrap.css index 6167622cec..057ff46dae 100644 --- a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/dist/css/bootstrap.css +++ b/apache-tapestry/src/main/webapp/mybootstrap/css/bootstrap.css @@ -1,9 +1,10 @@ /*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ -/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ + +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ html { font-family: sans-serif; -webkit-text-size-adjust: 100%; @@ -238,6 +239,9 @@ th { h3 { page-break-after: avoid; } + select { + background: #fff !important; + } .navbar { display: none; } @@ -279,10 +283,10 @@ th { -moz-osx-font-smoothing: grayscale; } .glyphicon-asterisk:before { - content: "\002a"; + content: "\2a"; } .glyphicon-plus:before { - content: "\002b"; + content: "\2b"; } .glyphicon-euro:before, .glyphicon-eur:before { @@ -1106,6 +1110,7 @@ a:focus { text-decoration: underline; } a:focus { + outline: thin dotted; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } @@ -1339,72 +1344,62 @@ mark, .text-primary { color: #337ab7; } -a.text-primary:hover, -a.text-primary:focus { +a.text-primary:hover { color: #286090; } .text-success { color: #3c763d; } -a.text-success:hover, -a.text-success:focus { +a.text-success:hover { color: #2b542c; } .text-info { color: #31708f; } -a.text-info:hover, -a.text-info:focus { +a.text-info:hover { color: #245269; } .text-warning { color: #8a6d3b; } -a.text-warning:hover, -a.text-warning:focus { +a.text-warning:hover { color: #66512c; } .text-danger { color: #a94442; } -a.text-danger:hover, -a.text-danger:focus { +a.text-danger:hover { color: #843534; } .bg-primary { color: #fff; background-color: #337ab7; } -a.bg-primary:hover, -a.bg-primary:focus { +a.bg-primary:hover { background-color: #286090; } .bg-success { background-color: #dff0d8; } -a.bg-success:hover, -a.bg-success:focus { +a.bg-success:hover { background-color: #c1e2b3; } .bg-info { background-color: #d9edf7; } -a.bg-info:hover, -a.bg-info:focus { +a.bg-info:hover { background-color: #afd9ee; } .bg-warning { background-color: #fcf8e3; } -a.bg-warning:hover, -a.bg-warning:focus { +a.bg-warning:hover { background-color: #f7ecb5; } .bg-danger { background-color: #f2dede; } -a.bg-danger:hover, -a.bg-danger:focus { +a.bg-danger:hover { background-color: #e4b9b9; } .page-header { @@ -2536,6 +2531,7 @@ select[size] { input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus { + outline: thin dotted; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } @@ -2580,10 +2576,6 @@ output { .form-control::-webkit-input-placeholder { color: #999; } -.form-control::-ms-expand { - background-color: transparent; - border: 0; -} .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { @@ -2601,10 +2593,10 @@ input[type="search"] { -webkit-appearance: none; } @media screen and (-webkit-min-device-pixel-ratio: 0) { - input[type="date"].form-control, - input[type="time"].form-control, - input[type="datetime-local"].form-control, - input[type="month"].form-control { + input[type="date"], + input[type="time"], + input[type="datetime-local"], + input[type="month"] { line-height: 34px; } input[type="date"].input-sm, @@ -2726,18 +2718,18 @@ select[multiple].input-sm { line-height: 1.5; border-radius: 3px; } -.form-group-sm select.form-control { +select.form-group-sm .form-control { height: 30px; line-height: 30px; } -.form-group-sm textarea.form-control, -.form-group-sm select[multiple].form-control { +textarea.form-group-sm .form-control, +select[multiple].form-group-sm .form-control { height: auto; } .form-group-sm .form-control-static { height: 30px; min-height: 32px; - padding: 6px 10px; + padding: 5px 10px; font-size: 12px; line-height: 1.5; } @@ -2763,18 +2755,18 @@ select[multiple].input-lg { line-height: 1.3333333; border-radius: 6px; } -.form-group-lg select.form-control { +select.form-group-lg .form-control { height: 46px; line-height: 46px; } -.form-group-lg textarea.form-control, -.form-group-lg select[multiple].form-control { +textarea.form-group-lg .form-control, +select[multiple].form-group-lg .form-control { height: auto; } .form-group-lg .form-control-static { height: 46px; min-height: 38px; - padding: 11px 16px; + padding: 10px 16px; font-size: 18px; line-height: 1.3333333; } @@ -2796,16 +2788,12 @@ select[multiple].input-lg { text-align: center; pointer-events: none; } -.input-lg + .form-control-feedback, -.input-group-lg + .form-control-feedback, -.form-group-lg .form-control + .form-control-feedback { +.input-lg + .form-control-feedback { width: 46px; height: 46px; line-height: 46px; } -.input-sm + .form-control-feedback, -.input-group-sm + .form-control-feedback, -.form-group-sm .form-control + .form-control-feedback { +.input-sm + .form-control-feedback { width: 30px; height: 30px; line-height: 30px; @@ -2990,14 +2978,12 @@ select[multiple].input-lg { } @media (min-width: 768px) { .form-horizontal .form-group-lg .control-label { - padding-top: 11px; - font-size: 18px; + padding-top: 14.333333px; } } @media (min-width: 768px) { .form-horizontal .form-group-sm .control-label { padding-top: 6px; - font-size: 12px; } } .btn { @@ -3027,6 +3013,7 @@ select[multiple].input-lg { .btn.focus, .btn:active.focus, .btn.active.focus { + outline: thin dotted; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } @@ -3046,32 +3033,21 @@ select[multiple].input-lg { .btn.disabled, .btn[disabled], fieldset[disabled] .btn { + pointer-events: none; cursor: not-allowed; filter: alpha(opacity=65); -webkit-box-shadow: none; box-shadow: none; opacity: .65; } -a.btn.disabled, -fieldset[disabled] a.btn { - pointer-events: none; -} .btn-default { color: #333; background-color: #fff; border-color: #ccc; } +.btn-default:hover, .btn-default:focus, -.btn-default.focus { - color: #333; - background-color: #e6e6e6; - border-color: #8c8c8c; -} -.btn-default:hover { - color: #333; - background-color: #e6e6e6; - border-color: #adadad; -} +.btn-default.focus, .btn-default:active, .btn-default.active, .open > .dropdown-toggle.btn-default { @@ -3079,24 +3055,14 @@ fieldset[disabled] a.btn { background-color: #e6e6e6; border-color: #adadad; } -.btn-default:active:hover, -.btn-default.active:hover, -.open > .dropdown-toggle.btn-default:hover, -.btn-default:active:focus, -.btn-default.active:focus, -.open > .dropdown-toggle.btn-default:focus, -.btn-default:active.focus, -.btn-default.active.focus, -.open > .dropdown-toggle.btn-default.focus { - color: #333; - background-color: #d4d4d4; - border-color: #8c8c8c; -} .btn-default:active, .btn-default.active, .open > .dropdown-toggle.btn-default { background-image: none; } +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, .btn-default.disabled:hover, .btn-default[disabled]:hover, fieldset[disabled] .btn-default:hover, @@ -3105,7 +3071,13 @@ fieldset[disabled] .btn-default:hover, fieldset[disabled] .btn-default:focus, .btn-default.disabled.focus, .btn-default[disabled].focus, -fieldset[disabled] .btn-default.focus { +fieldset[disabled] .btn-default.focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { background-color: #fff; border-color: #ccc; } @@ -3118,17 +3090,9 @@ fieldset[disabled] .btn-default.focus { background-color: #337ab7; border-color: #2e6da4; } +.btn-primary:hover, .btn-primary:focus, -.btn-primary.focus { - color: #fff; - background-color: #286090; - border-color: #122b40; -} -.btn-primary:hover { - color: #fff; - background-color: #286090; - border-color: #204d74; -} +.btn-primary.focus, .btn-primary:active, .btn-primary.active, .open > .dropdown-toggle.btn-primary { @@ -3136,24 +3100,14 @@ fieldset[disabled] .btn-default.focus { background-color: #286090; border-color: #204d74; } -.btn-primary:active:hover, -.btn-primary.active:hover, -.open > .dropdown-toggle.btn-primary:hover, -.btn-primary:active:focus, -.btn-primary.active:focus, -.open > .dropdown-toggle.btn-primary:focus, -.btn-primary:active.focus, -.btn-primary.active.focus, -.open > .dropdown-toggle.btn-primary.focus { - color: #fff; - background-color: #204d74; - border-color: #122b40; -} .btn-primary:active, .btn-primary.active, .open > .dropdown-toggle.btn-primary { background-image: none; } +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, .btn-primary.disabled:hover, .btn-primary[disabled]:hover, fieldset[disabled] .btn-primary:hover, @@ -3162,7 +3116,13 @@ fieldset[disabled] .btn-primary:hover, fieldset[disabled] .btn-primary:focus, .btn-primary.disabled.focus, .btn-primary[disabled].focus, -fieldset[disabled] .btn-primary.focus { +fieldset[disabled] .btn-primary.focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { background-color: #337ab7; border-color: #2e6da4; } @@ -3175,17 +3135,9 @@ fieldset[disabled] .btn-primary.focus { background-color: #5cb85c; border-color: #4cae4c; } +.btn-success:hover, .btn-success:focus, -.btn-success.focus { - color: #fff; - background-color: #449d44; - border-color: #255625; -} -.btn-success:hover { - color: #fff; - background-color: #449d44; - border-color: #398439; -} +.btn-success.focus, .btn-success:active, .btn-success.active, .open > .dropdown-toggle.btn-success { @@ -3193,24 +3145,14 @@ fieldset[disabled] .btn-primary.focus { background-color: #449d44; border-color: #398439; } -.btn-success:active:hover, -.btn-success.active:hover, -.open > .dropdown-toggle.btn-success:hover, -.btn-success:active:focus, -.btn-success.active:focus, -.open > .dropdown-toggle.btn-success:focus, -.btn-success:active.focus, -.btn-success.active.focus, -.open > .dropdown-toggle.btn-success.focus { - color: #fff; - background-color: #398439; - border-color: #255625; -} .btn-success:active, .btn-success.active, .open > .dropdown-toggle.btn-success { background-image: none; } +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, .btn-success.disabled:hover, .btn-success[disabled]:hover, fieldset[disabled] .btn-success:hover, @@ -3219,7 +3161,13 @@ fieldset[disabled] .btn-success:hover, fieldset[disabled] .btn-success:focus, .btn-success.disabled.focus, .btn-success[disabled].focus, -fieldset[disabled] .btn-success.focus { +fieldset[disabled] .btn-success.focus, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { background-color: #5cb85c; border-color: #4cae4c; } @@ -3232,17 +3180,9 @@ fieldset[disabled] .btn-success.focus { background-color: #5bc0de; border-color: #46b8da; } +.btn-info:hover, .btn-info:focus, -.btn-info.focus { - color: #fff; - background-color: #31b0d5; - border-color: #1b6d85; -} -.btn-info:hover { - color: #fff; - background-color: #31b0d5; - border-color: #269abc; -} +.btn-info.focus, .btn-info:active, .btn-info.active, .open > .dropdown-toggle.btn-info { @@ -3250,24 +3190,14 @@ fieldset[disabled] .btn-success.focus { background-color: #31b0d5; border-color: #269abc; } -.btn-info:active:hover, -.btn-info.active:hover, -.open > .dropdown-toggle.btn-info:hover, -.btn-info:active:focus, -.btn-info.active:focus, -.open > .dropdown-toggle.btn-info:focus, -.btn-info:active.focus, -.btn-info.active.focus, -.open > .dropdown-toggle.btn-info.focus { - color: #fff; - background-color: #269abc; - border-color: #1b6d85; -} .btn-info:active, .btn-info.active, .open > .dropdown-toggle.btn-info { background-image: none; } +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, .btn-info.disabled:hover, .btn-info[disabled]:hover, fieldset[disabled] .btn-info:hover, @@ -3276,7 +3206,13 @@ fieldset[disabled] .btn-info:hover, fieldset[disabled] .btn-info:focus, .btn-info.disabled.focus, .btn-info[disabled].focus, -fieldset[disabled] .btn-info.focus { +fieldset[disabled] .btn-info.focus, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { background-color: #5bc0de; border-color: #46b8da; } @@ -3289,17 +3225,9 @@ fieldset[disabled] .btn-info.focus { background-color: #f0ad4e; border-color: #eea236; } +.btn-warning:hover, .btn-warning:focus, -.btn-warning.focus { - color: #fff; - background-color: #ec971f; - border-color: #985f0d; -} -.btn-warning:hover { - color: #fff; - background-color: #ec971f; - border-color: #d58512; -} +.btn-warning.focus, .btn-warning:active, .btn-warning.active, .open > .dropdown-toggle.btn-warning { @@ -3307,24 +3235,14 @@ fieldset[disabled] .btn-info.focus { background-color: #ec971f; border-color: #d58512; } -.btn-warning:active:hover, -.btn-warning.active:hover, -.open > .dropdown-toggle.btn-warning:hover, -.btn-warning:active:focus, -.btn-warning.active:focus, -.open > .dropdown-toggle.btn-warning:focus, -.btn-warning:active.focus, -.btn-warning.active.focus, -.open > .dropdown-toggle.btn-warning.focus { - color: #fff; - background-color: #d58512; - border-color: #985f0d; -} .btn-warning:active, .btn-warning.active, .open > .dropdown-toggle.btn-warning { background-image: none; } +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, .btn-warning.disabled:hover, .btn-warning[disabled]:hover, fieldset[disabled] .btn-warning:hover, @@ -3333,7 +3251,13 @@ fieldset[disabled] .btn-warning:hover, fieldset[disabled] .btn-warning:focus, .btn-warning.disabled.focus, .btn-warning[disabled].focus, -fieldset[disabled] .btn-warning.focus { +fieldset[disabled] .btn-warning.focus, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { background-color: #f0ad4e; border-color: #eea236; } @@ -3346,17 +3270,9 @@ fieldset[disabled] .btn-warning.focus { background-color: #d9534f; border-color: #d43f3a; } +.btn-danger:hover, .btn-danger:focus, -.btn-danger.focus { - color: #fff; - background-color: #c9302c; - border-color: #761c19; -} -.btn-danger:hover { - color: #fff; - background-color: #c9302c; - border-color: #ac2925; -} +.btn-danger.focus, .btn-danger:active, .btn-danger.active, .open > .dropdown-toggle.btn-danger { @@ -3364,24 +3280,14 @@ fieldset[disabled] .btn-warning.focus { background-color: #c9302c; border-color: #ac2925; } -.btn-danger:active:hover, -.btn-danger.active:hover, -.open > .dropdown-toggle.btn-danger:hover, -.btn-danger:active:focus, -.btn-danger.active:focus, -.open > .dropdown-toggle.btn-danger:focus, -.btn-danger:active.focus, -.btn-danger.active.focus, -.open > .dropdown-toggle.btn-danger.focus { - color: #fff; - background-color: #ac2925; - border-color: #761c19; -} .btn-danger:active, .btn-danger.active, .open > .dropdown-toggle.btn-danger { background-image: none; } +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, .btn-danger.disabled:hover, .btn-danger[disabled]:hover, fieldset[disabled] .btn-danger:hover, @@ -3390,7 +3296,13 @@ fieldset[disabled] .btn-danger:hover, fieldset[disabled] .btn-danger:focus, .btn-danger.disabled.focus, .btn-danger[disabled].focus, -fieldset[disabled] .btn-danger.focus { +fieldset[disabled] .btn-danger.focus, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { background-color: #d9534f; border-color: #d43f3a; } @@ -3506,7 +3418,6 @@ tbody.collapse.in { margin-left: 2px; vertical-align: middle; border-top: 4px dashed; - border-top: 4px solid \9; border-right: 4px solid transparent; border-left: 4px solid transparent; } @@ -3623,8 +3534,7 @@ tbody.collapse.in { .navbar-fixed-bottom .dropdown .caret { content: ""; border-top: 0; - border-bottom: 4px dashed; - border-bottom: 4px solid \9; + border-bottom: 4px solid; } .dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu { @@ -3672,7 +3582,6 @@ tbody.collapse.in { .btn-toolbar { margin-left: -5px; } -.btn-toolbar .btn, .btn-toolbar .btn-group, .btn-toolbar .input-group { float: left; @@ -3764,7 +3673,6 @@ tbody.collapse.in { border-radius: 0; } .btn-group-vertical > .btn:first-child:not(:last-child) { - border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 0; border-bottom-left-radius: 0; @@ -3772,7 +3680,6 @@ tbody.collapse.in { .btn-group-vertical > .btn:last-child:not(:first-child) { border-top-left-radius: 0; border-top-right-radius: 0; - border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; } .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { @@ -3830,9 +3737,6 @@ tbody.collapse.in { width: 100%; margin-bottom: 0; } -.input-group .form-control:focus { - z-index: 3; -} .input-group-lg > .form-control, .input-group-lg > .input-group-addon, .input-group-lg > .input-group-btn > .btn { @@ -3968,7 +3872,6 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } .input-group-btn:last-child > .btn, .input-group-btn:last-child > .btn-group { - z-index: 2; margin-left: -1px; } .nav { @@ -4744,7 +4647,6 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { .pagination > li > span:hover, .pagination > li > a:focus, .pagination > li > span:focus { - z-index: 2; color: #23527c; background-color: #eee; border-color: #ddd; @@ -4755,7 +4657,7 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { .pagination > .active > span:hover, .pagination > .active > a:focus, .pagination > .active > span:focus { - z-index: 3; + z-index: 2; color: #fff; cursor: default; background-color: #337ab7; @@ -4776,7 +4678,6 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { .pagination-lg > li > span { padding: 10px 16px; font-size: 18px; - line-height: 1.3333333; } .pagination-lg > li:first-child > a, .pagination-lg > li:first-child > span { @@ -4792,7 +4693,6 @@ fieldset[disabled] .navbar-inverse .btn-link:focus { .pagination-sm > li > span { padding: 5px 10px; font-size: 12px; - line-height: 1.5; } .pagination-sm > li:first-child > a, .pagination-sm > li:first-child > span { @@ -4919,7 +4819,7 @@ a.label:focus { color: #fff; text-align: center; white-space: nowrap; - vertical-align: middle; + vertical-align: baseline; background-color: #777; border-radius: 10px; } @@ -4956,8 +4856,7 @@ a.badge:focus { margin-left: 3px; } .jumbotron { - padding-top: 30px; - padding-bottom: 30px; + padding: 30px 15px; margin-bottom: 30px; color: inherit; background-color: #eee; @@ -4976,8 +4875,6 @@ a.badge:focus { } .container .jumbotron, .container-fluid .jumbotron { - padding-right: 15px; - padding-left: 15px; border-radius: 6px; } .jumbotron .container { @@ -4985,8 +4882,7 @@ a.badge:focus { } @media screen and (min-width: 768px) { .jumbotron { - padding-top: 48px; - padding-bottom: 48px; + padding: 48px 0; } .container .jumbotron, .container-fluid .jumbotron { @@ -5210,9 +5106,6 @@ a.thumbnail.active { .media-object { display: block; } -.media-object.img-thumbnail { - max-width: none; -} .media-right, .media > .pull-right { padding-left: 10px; @@ -5262,26 +5155,18 @@ a.thumbnail.active { border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; } -a.list-group-item, -button.list-group-item { +a.list-group-item { color: #555; } -a.list-group-item .list-group-item-heading, -button.list-group-item .list-group-item-heading { +a.list-group-item .list-group-item-heading { color: #333; } a.list-group-item:hover, -button.list-group-item:hover, -a.list-group-item:focus, -button.list-group-item:focus { +a.list-group-item:focus { color: #555; text-decoration: none; background-color: #f5f5f5; } -button.list-group-item { - width: 100%; - text-align: left; -} .list-group-item.disabled, .list-group-item.disabled:hover, .list-group-item.disabled:focus { @@ -5327,27 +5212,20 @@ button.list-group-item { color: #3c763d; background-color: #dff0d8; } -a.list-group-item-success, -button.list-group-item-success { +a.list-group-item-success { color: #3c763d; } -a.list-group-item-success .list-group-item-heading, -button.list-group-item-success .list-group-item-heading { +a.list-group-item-success .list-group-item-heading { color: inherit; } a.list-group-item-success:hover, -button.list-group-item-success:hover, -a.list-group-item-success:focus, -button.list-group-item-success:focus { +a.list-group-item-success:focus { color: #3c763d; background-color: #d0e9c6; } a.list-group-item-success.active, -button.list-group-item-success.active, a.list-group-item-success.active:hover, -button.list-group-item-success.active:hover, -a.list-group-item-success.active:focus, -button.list-group-item-success.active:focus { +a.list-group-item-success.active:focus { color: #fff; background-color: #3c763d; border-color: #3c763d; @@ -5356,27 +5234,20 @@ button.list-group-item-success.active:focus { color: #31708f; background-color: #d9edf7; } -a.list-group-item-info, -button.list-group-item-info { +a.list-group-item-info { color: #31708f; } -a.list-group-item-info .list-group-item-heading, -button.list-group-item-info .list-group-item-heading { +a.list-group-item-info .list-group-item-heading { color: inherit; } a.list-group-item-info:hover, -button.list-group-item-info:hover, -a.list-group-item-info:focus, -button.list-group-item-info:focus { +a.list-group-item-info:focus { color: #31708f; background-color: #c4e3f3; } a.list-group-item-info.active, -button.list-group-item-info.active, a.list-group-item-info.active:hover, -button.list-group-item-info.active:hover, -a.list-group-item-info.active:focus, -button.list-group-item-info.active:focus { +a.list-group-item-info.active:focus { color: #fff; background-color: #31708f; border-color: #31708f; @@ -5385,27 +5256,20 @@ button.list-group-item-info.active:focus { color: #8a6d3b; background-color: #fcf8e3; } -a.list-group-item-warning, -button.list-group-item-warning { +a.list-group-item-warning { color: #8a6d3b; } -a.list-group-item-warning .list-group-item-heading, -button.list-group-item-warning .list-group-item-heading { +a.list-group-item-warning .list-group-item-heading { color: inherit; } a.list-group-item-warning:hover, -button.list-group-item-warning:hover, -a.list-group-item-warning:focus, -button.list-group-item-warning:focus { +a.list-group-item-warning:focus { color: #8a6d3b; background-color: #faf2cc; } a.list-group-item-warning.active, -button.list-group-item-warning.active, a.list-group-item-warning.active:hover, -button.list-group-item-warning.active:hover, -a.list-group-item-warning.active:focus, -button.list-group-item-warning.active:focus { +a.list-group-item-warning.active:focus { color: #fff; background-color: #8a6d3b; border-color: #8a6d3b; @@ -5414,27 +5278,20 @@ button.list-group-item-warning.active:focus { color: #a94442; background-color: #f2dede; } -a.list-group-item-danger, -button.list-group-item-danger { +a.list-group-item-danger { color: #a94442; } -a.list-group-item-danger .list-group-item-heading, -button.list-group-item-danger .list-group-item-heading { +a.list-group-item-danger .list-group-item-heading { color: inherit; } a.list-group-item-danger:hover, -button.list-group-item-danger:hover, -a.list-group-item-danger:focus, -button.list-group-item-danger:focus { +a.list-group-item-danger:focus { color: #a94442; background-color: #ebcccc; } a.list-group-item-danger.active, -button.list-group-item-danger.active, a.list-group-item-danger.active:hover, -button.list-group-item-danger.active:hover, -a.list-group-item-danger.active:focus, -button.list-group-item-danger.active:focus { +a.list-group-item-danger.active:focus { color: #fff; background-color: #a94442; border-color: #a94442; @@ -5508,10 +5365,6 @@ button.list-group-item-danger.active:focus { border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; } -.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { - border-top-left-radius: 0; - border-top-right-radius: 0; -} .panel-heading + .list-group .list-group-item:first-child { border-top-width: 0; } @@ -5932,6 +5785,7 @@ button.close { opacity: .5; } .modal-header { + min-height: 16.42857143px; padding: 15px; border-bottom: 1px solid #e5e5e5; } @@ -5992,23 +5846,10 @@ button.close { display: block; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 12px; - font-style: normal; font-weight: normal; - line-height: 1.42857143; - text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-break: normal; - word-spacing: normal; - word-wrap: normal; - white-space: normal; + line-height: 1.4; filter: alpha(opacity=0); opacity: 0; - - line-break: auto; } .tooltip.in { filter: alpha(opacity=90); @@ -6035,6 +5876,7 @@ button.close { padding: 3px 8px; color: #fff; text-align: center; + text-decoration: none; background-color: #000; border-radius: 4px; } @@ -6111,18 +5953,9 @@ button.close { padding: 1px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; - font-style: normal; font-weight: normal; line-height: 1.42857143; text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-break: normal; - word-spacing: normal; - word-wrap: normal; white-space: normal; background-color: #fff; -webkit-background-clip: padding-box; @@ -6132,8 +5965,6 @@ button.close { border-radius: 6px; -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); box-shadow: 0 5px 10px rgba(0, 0, 0, .2); - - line-break: auto; } .popover.top { margin-top: -10px; @@ -6261,8 +6092,8 @@ button.close { -webkit-backface-visibility: hidden; backface-visibility: hidden; - -webkit-perspective: 1000px; - perspective: 1000px; + -webkit-perspective: 1000; + perspective: 1000; } .carousel-inner > .item.next, .carousel-inner > .item.active.right { @@ -6324,7 +6155,6 @@ button.close { color: #fff; text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, .6); - background-color: rgba(0, 0, 0, 0); filter: alpha(opacity=50); opacity: .5; } @@ -6362,7 +6192,6 @@ button.close { top: 50%; z-index: 5; display: inline-block; - margin-top: -10px; } .carousel-control .icon-prev, .carousel-control .glyphicon-chevron-left { @@ -6378,6 +6207,7 @@ button.close { .carousel-control .icon-next { width: 20px; height: 20px; + margin-top: -10px; font-family: serif; line-height: 1; } @@ -6438,16 +6268,16 @@ button.close { .carousel-control .icon-next { width: 30px; height: 30px; - margin-top: -10px; + margin-top: -15px; font-size: 30px; } .carousel-control .glyphicon-chevron-left, .carousel-control .icon-prev { - margin-left: -10px; + margin-left: -15px; } .carousel-control .glyphicon-chevron-right, .carousel-control .icon-next { - margin-right: -10px; + margin-right: -15px; } .carousel-caption { right: 20%; @@ -6486,8 +6316,6 @@ button.close { .pager:after, .panel-body:before, .panel-body:after, -.modal-header:before, -.modal-header:after, .modal-footer:before, .modal-footer:after { display: table; @@ -6507,7 +6335,6 @@ button.close { .navbar-collapse:after, .pager:after, .panel-body:after, -.modal-header:after, .modal-footer:after { clear: both; } @@ -6572,7 +6399,7 @@ button.close { display: block !important; } table.visible-xs { - display: table !important; + display: table; } tr.visible-xs { display: table-row !important; @@ -6602,7 +6429,7 @@ button.close { display: block !important; } table.visible-sm { - display: table !important; + display: table; } tr.visible-sm { display: table-row !important; @@ -6632,7 +6459,7 @@ button.close { display: block !important; } table.visible-md { - display: table !important; + display: table; } tr.visible-md { display: table-row !important; @@ -6662,7 +6489,7 @@ button.close { display: block !important; } table.visible-lg { - display: table !important; + display: table; } tr.visible-lg { display: table-row !important; @@ -6715,7 +6542,7 @@ button.close { display: block !important; } table.visible-print { - display: table !important; + display: table; } tr.visible-print { display: table-row !important; @@ -6754,4 +6581,8 @@ button.close { display: none !important; } } -/*# sourceMappingURL=bootstrap.css.map */ + +/* tapestry-quickstart customizations start here: */ + +body { padding-top: 70px; } + diff --git a/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.eot b/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000000..9879fec538 Binary files /dev/null and b/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.eot differ diff --git a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg b/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.svg similarity index 100% rename from jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg rename to apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.svg diff --git a/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.ttf b/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000..c0e841e44b Binary files /dev/null and b/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.ttf differ diff --git a/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff b/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 0000000000..59d837ee61 Binary files /dev/null and b/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff differ diff --git a/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff2 b/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 0000000000..006d10650b Binary files /dev/null and b/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff2 differ diff --git a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/affix.js b/apache-tapestry/src/main/webapp/mybootstrap/js/affix.js similarity index 96% rename from jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/affix.js rename to apache-tapestry/src/main/webapp/mybootstrap/js/affix.js index 7f6516818a..98197642aa 100644 --- a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/affix.js +++ b/apache-tapestry/src/main/webapp/mybootstrap/js/affix.js @@ -1,8 +1,8 @@ /* ======================================================================== - * Bootstrap: affix.js v3.3.7 + * Bootstrap: affix.js v3.3.4 * http://getbootstrap.com/javascript/#affix * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. + * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -28,7 +28,7 @@ this.checkPosition() } - Affix.VERSION = '3.3.7' + Affix.VERSION = '3.3.4' Affix.RESET = 'affix affix-top affix-bottom' @@ -78,7 +78,7 @@ var offset = this.options.offset var offsetTop = offset.top var offsetBottom = offset.bottom - var scrollHeight = Math.max($(document).height(), $(document.body).height()) + var scrollHeight = $(document.body).height() if (typeof offset != 'object') offsetBottom = offsetTop = offset if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) diff --git a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/alert.js b/apache-tapestry/src/main/webapp/mybootstrap/js/alert.js similarity index 93% rename from jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/alert.js rename to apache-tapestry/src/main/webapp/mybootstrap/js/alert.js index db97f3b02b..1925ef011c 100644 --- a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/alert.js +++ b/apache-tapestry/src/main/webapp/mybootstrap/js/alert.js @@ -1,8 +1,8 @@ /* ======================================================================== - * Bootstrap: alert.js v3.3.7 + * Bootstrap: alert.js v3.3.4 * http://getbootstrap.com/javascript/#alerts * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. + * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -18,7 +18,7 @@ $(el).on('click', dismiss, this.close) } - Alert.VERSION = '3.3.7' + Alert.VERSION = '3.3.4' Alert.TRANSITION_DURATION = 150 @@ -31,7 +31,7 @@ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 } - var $parent = $(selector === '#' ? [] : selector) + var $parent = $(selector) if (e) e.preventDefault() diff --git a/apache-tapestry/src/main/webapp/mybootstrap/js/button.js b/apache-tapestry/src/main/webapp/mybootstrap/js/button.js new file mode 100644 index 0000000000..7c7c021f95 --- /dev/null +++ b/apache-tapestry/src/main/webapp/mybootstrap/js/button.js @@ -0,0 +1,116 @@ +/* ======================================================================== + * Bootstrap: button.js v3.3.4 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.VERSION = '3.3.4' + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (data.resetText == null) $el.data('resetText', $el[val]()) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + $el[val](data[state] == null ? this.options[state] : data[state]) + + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && this.$element.hasClass('active')) changed = false + else $parent.find('.active').removeClass('active') + } + if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } else { + this.$element.attr('aria-pressed', !this.$element.hasClass('active')) + } + + if (changed) this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + var old = $.fn.button + + $.fn.button = Plugin + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document) + .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + Plugin.call($btn, 'toggle') + e.preventDefault() + }) + .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { + $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) + }) + +}(jQuery); diff --git a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/carousel.js b/apache-tapestry/src/main/webapp/mybootstrap/js/carousel.js similarity index 98% rename from jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/carousel.js rename to apache-tapestry/src/main/webapp/mybootstrap/js/carousel.js index 6ff954c9bd..a38ef14d0b 100644 --- a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/carousel.js +++ b/apache-tapestry/src/main/webapp/mybootstrap/js/carousel.js @@ -1,8 +1,8 @@ /* ======================================================================== - * Bootstrap: carousel.js v3.3.7 + * Bootstrap: carousel.js v3.3.4 * http://getbootstrap.com/javascript/#carousel * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. + * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -30,7 +30,7 @@ .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) } - Carousel.VERSION = '3.3.7' + Carousel.VERSION = '3.3.4' Carousel.TRANSITION_DURATION = 600 diff --git a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/collapse.js b/apache-tapestry/src/main/webapp/mybootstrap/js/collapse.js similarity index 97% rename from jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/collapse.js rename to apache-tapestry/src/main/webapp/mybootstrap/js/collapse.js index 12038693d9..954513c5e1 100644 --- a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/collapse.js +++ b/apache-tapestry/src/main/webapp/mybootstrap/js/collapse.js @@ -1,12 +1,11 @@ /* ======================================================================== - * Bootstrap: collapse.js v3.3.7 + * Bootstrap: collapse.js v3.3.4 * http://getbootstrap.com/javascript/#collapse * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. + * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ -/* jshint latedef: false */ +function ($) { 'use strict'; @@ -30,7 +29,7 @@ if (this.options.toggle) this.toggle() } - Collapse.VERSION = '3.3.7' + Collapse.VERSION = '3.3.4' Collapse.TRANSITION_DURATION = 350 diff --git a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/dropdown.js b/apache-tapestry/src/main/webapp/mybootstrap/js/dropdown.js similarity index 82% rename from jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/dropdown.js rename to apache-tapestry/src/main/webapp/mybootstrap/js/dropdown.js index 04e9c2de47..9874600f9d 100644 --- a/jhipster/jhipster-microservice/gateway-app/src/main/webapp/bower_components/bootstrap/js/dropdown.js +++ b/apache-tapestry/src/main/webapp/mybootstrap/js/dropdown.js @@ -1,8 +1,8 @@ /* ======================================================================== - * Bootstrap: dropdown.js v3.3.7 + * Bootstrap: dropdown.js v3.3.4 * http://getbootstrap.com/javascript/#dropdowns * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. + * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -19,41 +19,7 @@ $(element).on('click.bs.dropdown', this.toggle) } - Dropdown.VERSION = '3.3.7' - - function getParent($this) { - var selector = $this.attr('data-target') - - if (!selector) { - selector = $this.attr('href') - selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 - } - - var $parent = selector && $(selector) - - return $parent && $parent.length ? $parent : $this.parent() - } - - function clearMenus(e) { - if (e && e.which === 3) return - $(backdrop).remove() - $(toggle).each(function () { - var $this = $(this) - var $parent = getParent($this) - var relatedTarget = { relatedTarget: this } - - if (!$parent.hasClass('open')) return - - if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return - - $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)) - - if (e.isDefaultPrevented()) return - - $this.attr('aria-expanded', 'false') - $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget)) - }) - } + Dropdown.VERSION = '3.3.4' Dropdown.prototype.toggle = function (e) { var $this = $(this) @@ -68,10 +34,7 @@ if (!isActive) { if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { // if mobile we use a backdrop because click events don't delegate - $(document.createElement('div')) - .addClass('dropdown-backdrop') - .insertAfter($(this)) - .on('click', clearMenus) + $('