();
+ init(treeSet);
+
+ // // 元素不允许为null
+ // treeSet.add(null);
+ // treeSet.add(null);
+
+ output(treeSet);
+ }
+
+ public static void main(String[] args)
+ {
+ System.out.println("采用HashSet");
+ Sets.testHashSet();
+ System.out.println();
+
+ System.out.println("采用LinkedHashSet --保持放入顺序");
+ Sets.testLinkedHashSet();
+ System.out.println();
+
+ System.out.println("采用TreeSet --按元素排序");
+ Sets.testTreeSet();
+ System.out.println();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/java4android/equals/EqualsTest.java b/basicKnowledge/src/com/xdc/basic/api/java4android/equals/EqualsTest.java
similarity index 84%
rename from basicKnowledge/src/com/xdc/basic/java4android/equals/EqualsTest.java
rename to basicKnowledge/src/com/xdc/basic/api/java4android/equals/EqualsTest.java
index fe6097a9..13173622 100644
--- a/basicKnowledge/src/com/xdc/basic/java4android/equals/EqualsTest.java
+++ b/basicKnowledge/src/com/xdc/basic/api/java4android/equals/EqualsTest.java
@@ -1,25 +1,30 @@
-package com.xdc.basic.java4android.equals;
-
-//测试代码
-public class EqualsTest
-{
- public static void main(String[] args)
- {
- User u1 = new User();
- User u2 = new User();
- User u3 = u1;
-
- u1.name = "gengxue";
- u1.age = 23;
- u2.name = "xudachao";
- u2.age = 24;
-
- System.out.println("u1 == u2 : " + (u1 == u2));
- System.out.println("u1 == u3 : " + (u1 == u3));
- System.out.println("u2 == u3 : " + (u2 == u3));
-
- System.out.println("u1.equals(u2) : " + u1.equals(u2));
- System.out.println("u1.equals(u3) : " + u1.equals(u3));
- System.out.println("u2.equals(u3) : " + u2.equals(u3));
- }
-}
+package com.xdc.basic.api.java4android.equals;
+
+/**
+ * equals方法测试类
+ *
+ * @author xdc
+ *
+ */
+public class EqualsTest
+{
+ public static void main(String[] args)
+ {
+ User u1 = new User();
+ User u2 = new User();
+ User u3 = u1;
+
+ u1.name = "gengxue";
+ u1.age = 23;
+ u2.name = "xudachao";
+ u2.age = 24;
+
+ System.out.println("u1 == u2 : " + (u1 == u2));
+ System.out.println("u1 == u3 : " + (u1 == u3));
+ System.out.println("u2 == u3 : " + (u2 == u3));
+
+ System.out.println("u1.equals(u2) : " + u1.equals(u2));
+ System.out.println("u1.equals(u3) : " + u1.equals(u3));
+ System.out.println("u2.equals(u3) : " + u2.equals(u3));
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/java4android/equals/User.java b/basicKnowledge/src/com/xdc/basic/api/java4android/equals/User.java
new file mode 100644
index 00000000..fb0ae32b
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/java4android/equals/User.java
@@ -0,0 +1,31 @@
+package com.xdc.basic.api.java4android.equals;
+
+//equals()的重写
+public class User
+{
+ String name;
+ int age;
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+
+ if (obj instanceof User)
+ {
+ User user = (User) obj;
+ if (this.name.equals(user.name) && this.age == user.age)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/java4android/io/BufferedReaderTest.java b/basicKnowledge/src/com/xdc/basic/api/java4android/io/BufferedReaderTest.java
similarity index 71%
rename from basicKnowledge/src/com/xdc/basic/java4android/io/BufferedReaderTest.java
rename to basicKnowledge/src/com/xdc/basic/api/java4android/io/BufferedReaderTest.java
index 25b3c707..0eaf8adc 100644
--- a/basicKnowledge/src/com/xdc/basic/java4android/io/BufferedReaderTest.java
+++ b/basicKnowledge/src/com/xdc/basic/api/java4android/io/BufferedReaderTest.java
@@ -1,38 +1,47 @@
-package com.xdc.basic.java4android.io;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-
-// 处理流示例
-class BufferedReaderTest
-{
- public static void main(String[] args)
- {
- FileReader fileReader = null;
- BufferedReader bufferedReader = null;
- try
- {
- fileReader = new FileReader("src\\com\\xdc\\basic\\java4android\\io\\from.txt");
- bufferedReader = new BufferedReader(fileReader);
- String line = null;
- while ((line = bufferedReader.readLine()) != null)
- System.out.println(line);
- }
- catch (Exception e)
- {
- System.out.println(e);
- }
- finally
- {
- try
- {
- bufferedReader.close();
- fileReader.close();
- }
- catch (Exception e)
- {
- System.out.println(e);
- }
- }
- }
-}
+package com.xdc.basic.api.java4android.io;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+
+import com.xdc.basic.skills.GetCurPath;
+
+/**
+ * 处理流示例
+ *
+ * @author xdc
+ *
+ */
+class BufferedReaderTest
+{
+ public static void main(String[] args)
+ {
+ String curPath = GetCurPath.getCurPath();
+
+ FileReader fileReader = null;
+ BufferedReader bufferedReader = null;
+ try
+ {
+ fileReader = new FileReader(curPath + "from.txt");
+ bufferedReader = new BufferedReader(fileReader);
+ String line = null;
+ while ((line = bufferedReader.readLine()) != null)
+ System.out.println(line);
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ finally
+ {
+ try
+ {
+ bufferedReader.close();
+ fileReader.close();
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/java4android/io/IOByteStreamTest.java b/basicKnowledge/src/com/xdc/basic/api/java4android/io/IOByteStreamTest.java
similarity index 74%
rename from basicKnowledge/src/com/xdc/basic/java4android/io/IOByteStreamTest.java
rename to basicKnowledge/src/com/xdc/basic/api/java4android/io/IOByteStreamTest.java
index 8f98bb35..49f8789f 100644
--- a/basicKnowledge/src/com/xdc/basic/java4android/io/IOByteStreamTest.java
+++ b/basicKnowledge/src/com/xdc/basic/api/java4android/io/IOByteStreamTest.java
@@ -1,21 +1,30 @@
-package com.xdc.basic.java4android.io;
+package com.xdc.basic.api.java4android.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-// io字节流示例
+import com.xdc.basic.skills.GetCurPath;
+
+/**
+ * io字节流示例
+ *
+ * @author xdc
+ *
+ */
class IOByteStreamTest
{
public static void main(String[] args)
{
+ String curPath = GetCurPath.getCurPath();
+
// 声明输入流、输出流引用
FileInputStream fis = null;
FileOutputStream fos = null;
try
{
// 生成代表输入流、输出流的对象
- fis = new FileInputStream("src\\com\\xdc\\basic\\java4android\\io\\from.txt");
- fos = new FileOutputStream("src\\com\\xdc\\basic\\java4android\\io\\to.txt");
+ fis = new FileInputStream(curPath + "from.txt");
+ fos = new FileOutputStream(curPath + "to.txt");
// 生成一个字节数组
byte[] buffer = new byte[1024];
int len;
diff --git a/basicKnowledge/src/com/xdc/basic/java4android/io/IOCharStreamTest.java b/basicKnowledge/src/com/xdc/basic/api/java4android/io/IOCharStreamTest.java
similarity index 68%
rename from basicKnowledge/src/com/xdc/basic/java4android/io/IOCharStreamTest.java
rename to basicKnowledge/src/com/xdc/basic/api/java4android/io/IOCharStreamTest.java
index cb3bf6e8..b1b8e937 100644
--- a/basicKnowledge/src/com/xdc/basic/java4android/io/IOCharStreamTest.java
+++ b/basicKnowledge/src/com/xdc/basic/api/java4android/io/IOCharStreamTest.java
@@ -1,44 +1,53 @@
-package com.xdc.basic.java4android.io;
-
-import java.io.FileReader;
-import java.io.FileWriter;
-
-// io字符流测试
-class IOCharStreamTest
-{
- public static void main(String[] args)
- {
- FileReader fr = null;
- FileWriter fw = null;
- try
- {
- fr = new FileReader("src\\com\\xdc\\basic\\java4android\\io\\from.txt");
- fw = new FileWriter("src\\com\\xdc\\basic\\java4android\\io\\to.txt");
- char[] buffer = new char[1024];
- int len;
- while ((len = fr.read(buffer, 0, buffer.length)) != -1)
- {
- fw.write(buffer, 0, len);
- String s = new String(buffer);
- s = s.trim();
- System.out.println(s);
- }
- }
- catch (Exception e)
- {
- System.out.println(e);
- }
- finally
- {
- try
- {
- fr.close();
- fw.close();
- }
- catch (Exception e)
- {
- System.out.println(e);
- }
- }
- }
-}
+package com.xdc.basic.api.java4android.io;
+
+import java.io.FileReader;
+import java.io.FileWriter;
+
+import com.xdc.basic.skills.GetCurPath;
+
+/**
+ * io字符流测试
+ *
+ * @author xdc
+ *
+ */
+class IOCharStreamTest
+{
+ public static void main(String[] args)
+ {
+ String curPath = GetCurPath.getCurPath();
+
+ FileReader fr = null;
+ FileWriter fw = null;
+ try
+ {
+ fr = new FileReader(curPath + "from.txt");
+ fw = new FileWriter(curPath + "to.txt");
+ char[] buffer = new char[1024];
+ int len;
+ while ((len = fr.read(buffer, 0, buffer.length)) != -1)
+ {
+ fw.write(buffer, 0, len);
+ String s = new String(buffer);
+ s = s.trim();
+ System.out.println(s);
+ }
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ finally
+ {
+ try
+ {
+ fr.close();
+ fw.close();
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ }
+ }
+}
diff --git a/basicKnowledge/bin/com/xdc/basic/java4android/io/from.txt b/basicKnowledge/src/com/xdc/basic/api/java4android/io/from.txt
similarity index 100%
rename from basicKnowledge/bin/com/xdc/basic/java4android/io/from.txt
rename to basicKnowledge/src/com/xdc/basic/api/java4android/io/from.txt
diff --git a/basicKnowledge/bin/com/xdc/basic/java4android/io/to.txt b/basicKnowledge/src/com/xdc/basic/api/java4android/io/to.txt
similarity index 100%
rename from basicKnowledge/bin/com/xdc/basic/java4android/io/to.txt
rename to basicKnowledge/src/com/xdc/basic/api/java4android/io/to.txt
diff --git a/basicKnowledge/src/com/xdc/basic/api/jaxb/XMLConvertor.java b/basicKnowledge/src/com/xdc/basic/api/jaxb/XMLConvertor.java
new file mode 100644
index 00000000..c3e84392
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/jaxb/XMLConvertor.java
@@ -0,0 +1,86 @@
+package com.xdc.basic.api.jaxb;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+
+public class XMLConvertor
+{
+ private JAXBContext jaxbContext = null;
+ private Marshaller marshaller = null;
+ private Unmarshaller unmarshaller = null;
+
+ public XMLConvertor(String conextPath) throws JAXBException
+ {
+ jaxbContext = JAXBContext.newInstance(conextPath);
+ marshaller = jaxbContext.createMarshaller();
+ unmarshaller = jaxbContext.createUnmarshaller();
+ }
+
+ public Object xml2Java(Reader rd) throws JAXBException
+ {
+ return unmarshaller.unmarshal(rd);
+ }
+
+ public void java2Xml(Object obj, Writer wt) throws JAXBException
+ {
+ marshaller.marshal(obj, wt);
+ }
+
+ public Object xml2Java(InputStream is) throws JAXBException
+ {
+ return unmarshaller.unmarshal(is);
+ }
+
+ public void java2Xml(Object obj, OutputStream os) throws JAXBException
+ {
+ marshaller.marshal(obj, os);
+ }
+
+ public Object xml2Java(File file) throws JAXBException
+ {
+ return unmarshaller.unmarshal(file);
+ }
+
+ public void java2Xml(Object obj, File file) throws JAXBException
+ {
+ marshaller.marshal(obj, file);
+ }
+
+ public Object xmlString2Java(String xmlString) throws JAXBException
+ {
+ StringReader stringReader = new StringReader(xmlString);
+ return this.xml2Java(stringReader);
+ }
+
+ public String java2XmlString(Object obj) throws JAXBException
+ {
+ StringWriter stringWriter = new StringWriter();
+ this.java2Xml(obj, stringWriter);
+ return stringWriter.toString();
+ }
+
+ public Object xmlByte2Java(byte[] xmlByte) throws JAXBException
+ {
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(xmlByte);
+ return this.xml2Java(inputStream);
+ }
+
+ public byte[] java2XmlByte(Object obj) throws JAXBException
+ {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ this.java2Xml(obj, outputStream);
+ return outputStream.toByteArray();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/jaxb/XMLTest.java b/basicKnowledge/src/com/xdc/basic/api/jaxb/XMLTest.java
new file mode 100644
index 00000000..79e297a1
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/jaxb/XMLTest.java
@@ -0,0 +1,55 @@
+package com.xdc.basic.api.jaxb;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBException;
+
+import org.junit.Test;
+
+import com.xdc.basic.api.jaxb.user.Users;
+
+/**
+ * xml解析
+ *
+ * @author xdc
+ *
+ */
+public class XMLTest
+{
+ private final String usersXML = "小李男24小丽女18小王男22";
+
+ @Test
+ public void xmlString2Java() throws JAXBException
+ {
+ final String XML_MODEL_MEMBER = Users.class.getPackage().getName();
+
+ XMLConvertor xmlConvertor = new XMLConvertor(XML_MODEL_MEMBER);
+
+ StringReader stringReader = new StringReader(usersXML);
+ Users users = (Users) xmlConvertor.xml2Java(stringReader);
+ System.out.println(users);
+
+ StringWriter stringWriter = new StringWriter();
+ xmlConvertor.java2Xml(users, stringWriter);
+ System.out.println(stringWriter);
+ }
+
+ @Test
+ public void xmlBytes2Java() throws JAXBException
+ {
+ final String XML_MODEL_MEMBER = Users.class.getPackage().getName();
+
+ XMLConvertor xmlConvertor = new XMLConvertor(XML_MODEL_MEMBER);
+
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(usersXML.getBytes());
+ Users users = (Users) xmlConvertor.xml2Java(inputStream);
+ System.out.println(users);
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ xmlConvertor.java2Xml(users, outputStream);
+ System.out.println(outputStream.toString());
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/jaxb/user/ObjectFactory.java b/basicKnowledge/src/com/xdc/basic/api/jaxb/user/ObjectFactory.java
new file mode 100644
index 00000000..fc0105d3
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/jaxb/user/ObjectFactory.java
@@ -0,0 +1,93 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See http://java.sun.com/xml/jaxb
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2013.04.15 at 12:59:25 AM CST
+//
+
+
+package com.xdc.basic.api.jaxb.user;
+
+import java.math.BigInteger;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElementDecl;
+import javax.xml.bind.annotation.XmlRegistry;
+import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import javax.xml.namespace.QName;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the com.xdc.basic.example.jaxb.user package.
+ * An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ *
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+ private final static QName _Sex_QNAME = new QName("", "sex");
+ private final static QName _Age_QNAME = new QName("", "age");
+ private final static QName _Name_QNAME = new QName("", "name");
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.xdc.basic.example.jaxb.user
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link Users }
+ *
+ */
+ public Users createUsers() {
+ return new Users();
+ }
+
+ /**
+ * Create an instance of {@link User }
+ *
+ */
+ public User createUser() {
+ return new User();
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
+ *
+ */
+ @XmlElementDecl(namespace = "", name = "sex")
+ @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+ public JAXBElement createSex(String value) {
+ return new JAXBElement(_Sex_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link BigInteger }{@code >}}
+ *
+ */
+ @XmlElementDecl(namespace = "", name = "age")
+ public JAXBElement createAge(BigInteger value) {
+ return new JAXBElement(_Age_QNAME, BigInteger.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
+ *
+ */
+ @XmlElementDecl(namespace = "", name = "name")
+ @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+ public JAXBElement createName(String value) {
+ return new JAXBElement(_Name_QNAME, String.class, null, value);
+ }
+
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/jaxb/user/User.java b/basicKnowledge/src/com/xdc/basic/api/jaxb/user/User.java
new file mode 100644
index 00000000..c76b7e98
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/jaxb/user/User.java
@@ -0,0 +1,140 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See http://java.sun.com/xml/jaxb
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2013.04.15 at 12:59:25 AM CST
+//
+
+package com.xdc.basic.api.jaxb.user;
+
+import java.math.BigInteger;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ *
+ * Java class for anonymous complex type.
+ *
+ *
+ * The following schema fragment specifies the expected content contained within
+ * this class.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element ref="{}name"/>
+ * <element ref="{}sex"/>
+ * <element ref="{}age"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = { "name", "sex", "age" })
+@XmlRootElement(name = "user")
+public class User
+{
+
+ @XmlElement(required = true)
+ @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+ @XmlSchemaType(name = "NCName")
+ protected String name;
+ @XmlElement(required = true)
+ @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+ @XmlSchemaType(name = "NCName")
+ protected String sex;
+ @XmlElement(required = true)
+ protected BigInteger age;
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return possible object is {@link String }
+ *
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param value
+ * allowed object is {@link String }
+ *
+ */
+ public void setName(String value)
+ {
+ this.name = value;
+ }
+
+ /**
+ * Gets the value of the sex property.
+ *
+ * @return possible object is {@link String }
+ *
+ */
+ public String getSex()
+ {
+ return sex;
+ }
+
+ /**
+ * Sets the value of the sex property.
+ *
+ * @param value
+ * allowed object is {@link String }
+ *
+ */
+ public void setSex(String value)
+ {
+ this.sex = value;
+ }
+
+ /**
+ * Gets the value of the age property.
+ *
+ * @return possible object is {@link BigInteger }
+ *
+ */
+ public BigInteger getAge()
+ {
+ return age;
+ }
+
+ /**
+ * Sets the value of the age property.
+ *
+ * @param value
+ * allowed object is {@link BigInteger }
+ *
+ */
+ public void setAge(BigInteger value)
+ {
+ this.age = value;
+ }
+
+ @Override
+ public String toString()
+ {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
+ }
+
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/jaxb/user/Users.java b/basicKnowledge/src/com/xdc/basic/api/jaxb/user/Users.java
new file mode 100644
index 00000000..c047afdb
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/jaxb/user/Users.java
@@ -0,0 +1,89 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See http://java.sun.com/xml/jaxb
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2013.04.15 at 12:59:25 AM CST
+//
+
+package com.xdc.basic.api.jaxb.user;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ *
+ * Java class for anonymous complex type.
+ *
+ *
+ * The following schema fragment specifies the expected content contained within
+ * this class.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element ref="{}user" maxOccurs="unbounded"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = { "user" })
+@XmlRootElement(name = "users")
+public class Users
+{
+
+ @XmlElement(required = true)
+ protected List user;
+
+ /**
+ * Gets the value of the user property.
+ *
+ *
+ * This accessor method returns a reference to the live list, not a
+ * snapshot. Therefore any modification you make to the returned list will
+ * be present inside the JAXB object. This is why there is not a
+ * set method for the user property.
+ *
+ *
+ * For example, to add a new item, do as follows:
+ *
+ *
+ * getUser().add(newItem);
+ *
+ *
+ *
+ *
+ * Objects of the following type(s) are allowed in the list {@link User }
+ *
+ *
+ */
+ public List getUser()
+ {
+ if (user == null)
+ {
+ user = new ArrayList();
+ }
+ return this.user;
+ }
+
+ @Override
+ public String toString()
+ {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
+ }
+}
diff --git "a/basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/trang.jar" "b/basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/trang.jar"
new file mode 100644
index 00000000..672d65c4
Binary files /dev/null and "b/basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/trang.jar" differ
diff --git a/jdom2.format/users.xml "b/basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/users.xml"
similarity index 84%
rename from jdom2.format/users.xml
rename to "basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/users.xml"
index 3a400259..af30b881 100644
--- a/jdom2.format/users.xml
+++ "b/basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/users.xml"
@@ -1,6 +1,6 @@
- 小李
+ 小李
男 24
小丽
diff --git "a/basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/xml2xsd.bat" "b/basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/xml2xsd.bat"
new file mode 100644
index 00000000..47a7ba53
--- /dev/null
+++ "b/basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/xml2xsd.bat"
@@ -0,0 +1 @@
+java -jar trang.jar "users.xml" "users.xsd"
\ No newline at end of file
diff --git "a/basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/xsd2java.bat" "b/basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/xsd2java.bat"
new file mode 100644
index 00000000..689c04a1
--- /dev/null
+++ "b/basicKnowledge/src/com/xdc/basic/api/jaxb/\350\207\252\345\212\250\347\224\237\346\210\220\345\267\245\345\205\267/xsd2java.bat"
@@ -0,0 +1 @@
+xjc -xmlschema "users.xsd" -p com.xdc.basic.example.jaxb.user
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/json/jackson/JsonTool.java b/basicKnowledge/src/com/xdc/basic/api/json/jackson/JsonTool.java
new file mode 100644
index 00000000..50195882
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/json/jackson/JsonTool.java
@@ -0,0 +1,96 @@
+package com.xdc.basic.api.json.jackson;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class JsonTool
+{
+ private static final ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
+ static
+ {
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ }
+
+ public static void main(String[] args)
+ {
+ // ----------------------------------------------------------
+ // json object ----------------------------------------------
+ String jsonString = "{\"name\":{\"first\":\"Joe\",\"last\":\"Sixpack\"},\"gender\":\"MALE\",\"verified\":false,\"userImage\":\"Rm9vYmFyIQ==\"}";
+
+ // json string --> object
+ User user = JsonTool.parse(jsonString, User.class);
+ System.out.println(user);
+
+ // object --> json string
+ String jsonString2 = JsonTool.toJSONString(user);
+ System.out.println(jsonString2);
+
+ // ----------------------------------------------------------
+ // json array -----------------------------------------------
+ ArrayList users = new ArrayList();
+ users.add(user);
+ users.add(user);
+
+ // array --> json string
+ String jsonString3 = JsonTool.toJSONString(users);
+ System.out.println(jsonString3);
+
+ // json string --> array
+ User[] parsedUsers = JsonTool.parse(jsonString3, User[].class);
+ System.out.println(parsedUsers);
+ }
+
+ public static String toJSONString(Object o)
+ {
+ String s = null;
+ try
+ {
+ s = mapper.writeValueAsString(o);
+
+ // 漂亮的输出
+ // mapper.writerWithDefaultPrettyPrinter().writeValueAsString(o);
+ }
+ catch (JsonProcessingException e)
+ {
+ e.printStackTrace();
+ }
+ return s;
+ }
+
+ public static T parse(String s, Class clazz)
+ {
+ T t = null;
+ try
+ {
+ t = mapper.readValue(s, clazz);
+ }
+ catch (JsonParseException e)
+ {
+ e.printStackTrace();
+ }
+ catch (JsonMappingException e)
+ {
+ e.printStackTrace();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ return t;
+ }
+
+ public static List parseArray(String s, Class clazz)
+ {
+ // TODO 待研究
+ // List result = mapper.readValue(s, TypeFactory.collectionType(ArrayList.class, clazz));
+ // return result;
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/json/jackson/User.java b/basicKnowledge/src/com/xdc/basic/api/json/jackson/User.java
new file mode 100644
index 00000000..b2f0ee16
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/json/jackson/User.java
@@ -0,0 +1,79 @@
+package com.xdc.basic.api.json.jackson;
+
+public class User
+{
+ public enum Gender
+ {
+ MALE, FEMALE
+ };
+
+ public static class Name
+ {
+ private String _first, _last;
+
+ public String getFirst()
+ {
+ return _first;
+ }
+
+ public String getLast()
+ {
+ return _last;
+ }
+
+ public void setFirst(String s)
+ {
+ _first = s;
+ }
+
+ public void setLast(String s)
+ {
+ _last = s;
+ }
+ }
+
+ private Gender _gender;
+ private Name _name;
+ private boolean _isVerified;
+ private byte[] _userImage;
+
+ public Name getName()
+ {
+ return _name;
+ }
+
+ public boolean isVerified()
+ {
+ return _isVerified;
+ }
+
+ public Gender getGender()
+ {
+ return _gender;
+ }
+
+ public byte[] getUserImage()
+ {
+ return _userImage;
+ }
+
+ public void setName(Name n)
+ {
+ _name = n;
+ }
+
+ public void setVerified(boolean b)
+ {
+ _isVerified = b;
+ }
+
+ public void setGender(Gender g)
+ {
+ _gender = g;
+ }
+
+ public void setUserImage(byte[] b)
+ {
+ _userImage = b;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/json/jsonsmart/JsonDemo.java b/basicKnowledge/src/com/xdc/basic/api/json/jsonsmart/JsonDemo.java
new file mode 100644
index 00000000..84fb6053
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/json/jsonsmart/JsonDemo.java
@@ -0,0 +1,138 @@
+package com.xdc.basic.api.json.jsonsmart;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.minidev.json.JSONArray;
+import net.minidev.json.JSONObject;
+import net.minidev.json.JSONStyle;
+import net.minidev.json.JSONValue;
+import net.minidev.json.parser.JSONParser;
+import net.minidev.json.parser.ParseException;
+
+import org.junit.Test;
+
+/*
+ * Home page: http://code.google.com/p/json-smart/
+ *
+ */
+
+public class JsonDemo
+{
+ @Test
+ public void EncodeJsonObject()
+ {
+ // Json Object is an HashMap extends
+ JSONObject obj = new JSONObject();
+ obj.put("name", "foo");
+ obj.put("num", 100);
+ obj.put("balance", 1000.21);
+ obj.put("is_vip", true);
+ obj.put("nickname", null);
+
+ System.out.println("Standard RFC4627 JSON");
+ System.out.println(obj.toJSONString());
+ System.out.println("Compacted JSON Value");
+ System.out.println(obj.toJSONString(JSONStyle.MAX_COMPRESS));
+
+ // if obj is an common map you can use:
+ System.out.println("Standard RFC4627 JSON");
+ System.out.println(JSONValue.toJSONString(obj));
+ System.out.println("Compacted JSON Value");
+ System.out.println(JSONValue.toJSONString(obj, JSONStyle.MAX_COMPRESS));
+ }
+
+ @Test
+ public void DecodingJsonText() throws ParseException
+ {
+ System.out.println("=======decode=======");
+
+ String s = "[0,{'1':{'2':{'3':{'4':[5,{'6':7}]}}}}]";
+ Object obj = JSONValue.parse(s);
+ JSONArray array = (JSONArray) obj;
+ System.out.println("======the 2nd element of array======");
+ System.out.println(array.get(1));
+ System.out.println();
+
+ JSONObject obj2 = (JSONObject) array.get(1);
+ System.out.println("======field \"1\"==========");
+ System.out.println(obj2.get("1"));
+
+ s = "{}";
+ obj = JSONValue.parse(s);
+ System.out.println(obj);
+
+ s = "{\"key\":\"Value\"}";
+ // JSONValue.parseStrict()
+ // can be use to be sure that the input is wellformed
+ obj = JSONValue.parseStrict(s);
+ JSONObject obj3 = (JSONObject) obj;
+ System.out.println("====== Object content ======");
+ System.out.println(obj3.get("key"));
+ System.out.println();
+ }
+
+ @Test
+ public void DecodingJsonText2() throws ParseException
+ {
+ Student student = new Student("xudachao", 100, 25);
+ List goodFriends = new ArrayList();
+ goodFriends.add("chenchong");
+ goodFriends.add("duquan");
+ student.setGoodFriends(goodFriends);
+
+ String studentString = JSONValue.toJSONString(student);
+ System.out.println(studentString);
+
+ // Student必须有无参构造函数,因为利用反射获取对象
+ Student parsedStudent = JSONValue.parse(studentString, Student.class);
+ System.out.println(parsedStudent);
+
+ // smart json 还没提供直接数组串转会数组的方法
+ String goodFriendsString = JSONValue.toJSONString(goodFriends);
+ System.out.println(goodFriendsString);
+
+ // parse的结果只有两种可能 JSONObject或JSONArray
+ Object object = JSONValue.parse(studentString);
+ if (object instanceof JSONObject)
+ {
+ System.out.println("It,s a json object.");
+ }
+ else
+ {
+ System.out.println("It,s a json array.");
+ }
+ }
+
+ @Test
+ public void Merge2JsonObject() throws ParseException
+ {
+ String json1 = "{'car':{'color':'blue'}}";
+ String json2 = "{'car':{'size':'3.5m'}}";
+
+ @SuppressWarnings("deprecation")
+ JSONParser p = new JSONParser();
+ JSONObject o1 = (JSONObject) p.parse(json1);
+ JSONObject o2 = (JSONObject) p.parse(json2);
+
+ o1.merge(o2);
+
+ System.out.println(o1);
+ }
+
+ @Test
+ public void ValidatingJsonInput() throws ParseException
+ {
+ // JSONValue.isValidJson(String) To validate a string that conforms to the (non-strict) JSON Smart mode.
+ // JSONValue.isValidStrictJson(String) To validate a string of JSON for strict conformance to RFC4627.
+
+ String s = "{intValue:123}";
+ if (JSONValue.isValidJson(s))
+ System.out.println(s + " validates as Smart JSON");
+
+ if (JSONValue.isValidJsonStrict(s))
+ System.out.println(s + " validates as strict JSON");
+ else
+ System.out.println(s + " does not validate as strict JSON");
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/json/jsonsmart/JsonTool.java b/basicKnowledge/src/com/xdc/basic/api/json/jsonsmart/JsonTool.java
new file mode 100644
index 00000000..fd5629f3
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/json/jsonsmart/JsonTool.java
@@ -0,0 +1,76 @@
+package com.xdc.basic.api.json.jsonsmart;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.minidev.json.JSONArray;
+import net.minidev.json.JSONValue;
+
+import org.junit.Test;
+
+public class JsonTool
+{
+ @Test
+ public void jsonTest()
+ {
+ // ----------------------------------------------------------
+ // json object ----------------------------------------------
+ Student student = new Student("xudachao", 100, 25);
+ List goodFriends = new ArrayList();
+ goodFriends.add("chenchong");
+ goodFriends.add("duquan");
+ student.setGoodFriends(goodFriends);
+
+ // object --> json string
+ String studentString = JsonTool.toJSONString(student);
+ System.out.println(studentString);
+
+ // json string --> object
+ Student parsedStudent = JsonTool.parse(studentString, Student.class);
+ System.out.println(parsedStudent);
+
+ // ----------------------------------------------------------
+ // json array -----------------------------------------------
+ List students = new ArrayList();
+ students.add(student);
+ students.add(student);
+
+ // array --> json string
+ String studentsString = JSONValue.toJSONString(students);
+ System.out.println(studentsString);
+
+ // json string --> array
+ List parsedArray = JsonTool.parseArray(studentsString, Student.class);
+ System.out.println(parsedArray);
+
+ // json string --> array
+ Student[] parsedStudents = JsonTool.parse(studentsString, Student[].class);
+ System.out.println(parsedStudents);
+ }
+
+ public static String toJSONString(Object o)
+ {
+ return JSONValue.toJSONString(o);
+ }
+
+ public static T parse(String s, Class clazz)
+ {
+ return JSONValue.parse(s, clazz);
+ }
+
+ public static List parseArray(String s, Class clazz)
+ {
+ List result = new ArrayList();
+ Object object = JSONValue.parse(s);
+ if (object instanceof JSONArray)
+ {
+ JSONArray jsonArray = (JSONArray) object;
+ for (Object object2 : jsonArray)
+ {
+ String string = JSONValue.toJSONString(object2);
+ result.add(JSONValue.parse(string, clazz));
+ }
+ }
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/json/jsonsmart/Student.java b/basicKnowledge/src/com/xdc/basic/api/json/jsonsmart/Student.java
new file mode 100644
index 00000000..f0d44d27
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/json/jsonsmart/Student.java
@@ -0,0 +1,74 @@
+package com.xdc.basic.api.json.jsonsmart;
+
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+public class Student
+{
+ private String name;
+ private int score;
+ private int age;
+ private List goodFriends;
+
+ public Student()
+ {
+ super();
+ }
+
+ public Student(String name, int score, int age)
+ {
+ super();
+ this.setName(name);
+ this.setScore(score);
+ this.setAge(age);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public int getScore()
+ {
+ return score;
+ }
+
+ public void setScore(int score)
+ {
+ this.score = score;
+ }
+
+ public int getAge()
+ {
+ return age;
+ }
+
+ public void setAge(int age)
+ {
+ this.age = age;
+ }
+
+ @Override
+ public String toString()
+ {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
+ }
+
+ public List getGoodFriends()
+ {
+ return goodFriends;
+ }
+
+ public void setGoodFriends(List goodFriends)
+ {
+ this.goodFriends = goodFriends;
+ }
+
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/mq/Recv.java b/basicKnowledge/src/com/xdc/basic/api/mq/Recv.java
new file mode 100644
index 00000000..ac7ff1e5
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mq/Recv.java
@@ -0,0 +1,43 @@
+package com.xdc.basic.api.mq;
+
+import java.io.IOException;
+
+import com.rabbitmq.client.Channel;
+import com.rabbitmq.client.Connection;
+import com.rabbitmq.client.ConnectionFactory;
+import com.rabbitmq.client.ConsumerCancelledException;
+import com.rabbitmq.client.QueueingConsumer;
+import com.rabbitmq.client.ShutdownSignalException;
+
+/**
+ * mq消息接收示例 (需在开启RabbitMQ Server才能看到结果)
+ *
+ * @author xdc
+ *
+ */
+public class Recv
+{
+ private final static String QUEUE_NAME = "hello";
+
+ public static void main(String[] argv) throws IOException, ShutdownSignalException, ConsumerCancelledException,
+ InterruptedException
+ {
+ ConnectionFactory factory = new ConnectionFactory();
+ factory.setHost("localhost");
+ Connection connection = factory.newConnection();
+ Channel channel = connection.createChannel();
+
+ channel.queueDeclare(QUEUE_NAME, false, false, false, null);
+ System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
+
+ QueueingConsumer consumer = new QueueingConsumer(channel);
+ channel.basicConsume(QUEUE_NAME, true, consumer);
+
+ while (true)
+ {
+ QueueingConsumer.Delivery delivery = consumer.nextDelivery();
+ String message = new String(delivery.getBody());
+ System.out.println(" [x] Received '" + message + "'");
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/mq/Send.java b/basicKnowledge/src/com/xdc/basic/api/mq/Send.java
new file mode 100644
index 00000000..b94c8fc3
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mq/Send.java
@@ -0,0 +1,36 @@
+package com.xdc.basic.api.mq;
+
+import java.io.IOException;
+
+import com.rabbitmq.client.Channel;
+import com.rabbitmq.client.Connection;
+import com.rabbitmq.client.ConnectionFactory;
+
+/**
+ * mq消息发送示例
+ *
+ * @author xdc
+ *
+ */
+public class Send
+{
+ private final static String QUEUE_NAME = "hello";
+
+ public static void main(String[] args) throws IOException
+ {
+ ConnectionFactory factory = new ConnectionFactory();
+ factory.setHost("localhost");
+ Connection connection = factory.newConnection();
+ Channel channel = connection.createChannel();
+
+ channel.queueDeclare(QUEUE_NAME, false, false, false, null);
+ for (int i = 0; i < 5; i++)
+ {
+ String message = "Hello World!" + i;
+ channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
+ System.out.println(" [x] Sent '" + message + "'");
+ }
+ channel.close();
+ connection.close();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/MyBatisTest.java b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/MyBatisTest.java
new file mode 100644
index 00000000..a619080e
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/MyBatisTest.java
@@ -0,0 +1,64 @@
+package com.xdc.basic.api.mybatis.generator;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.session.SqlSessionFactoryBuilder;
+
+import com.xdc.basic.api.mybatis.generator.data.StudentMapper;
+import com.xdc.basic.api.mybatis.generator.model.Student;
+
+public class MyBatisTest
+{
+ public static void main(String[] args) throws IOException
+ {
+ String resource = "com/xdc/basic/example/mybatis/generator/data/mybatis-config.xml";
+ Reader reader = Resources.getResourceAsReader(resource);
+
+ SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
+
+ /*
+ * http://mybatis.github.io/mybatis-3/zh/java-api.html#sqlSessions
+ * 默认的 openSession()方法没有参数,它会创建有如下特性的 SqlSession:
+ * 1.会开启一个事务(也就是不自动提交)。
+ * 2.连接对象会从由活动环境配置的数据源实例中得到。
+ * 3.事务隔离级别将会使用驱动或数据源的默认设置。
+ * 4.预处理语句不会被复用,也不会批量处理更新。
+ */
+ SqlSession sqlSession = sqlSessionFactory.openSession();
+
+ try
+ {
+ StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
+
+ Student student = studentMapper.selectByPrimaryKey(4);
+ System.out.println("插入前:" + student);
+
+ studentMapper.insert(new Student(4, "耿雪", "女", "计算机科学与技术", "2008"));
+
+ student = studentMapper.selectByPrimaryKey(4);
+ System.out.println("提交前:" + student);
+
+ // 提交的意义在于:在其他的sqlSession中能够看见语句的结果,而在本身的sqlSession中,无论提交与否,都是可见的。
+ sqlSession.commit();
+
+ student = studentMapper.selectByPrimaryKey(4);
+ System.out.println("提交后:" + student);
+
+ studentMapper.deleteByPrimaryKey(4);
+
+ sqlSession.commit();
+
+ student = studentMapper.selectByPrimaryKey(4);
+ System.out.println("删除后:" + student);
+ }
+ finally
+ {
+ // 如果在关闭前都没有提交,那么前面的内容将自动回滚。
+ sqlSession.close();
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/data/StudentMapper.java b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/data/StudentMapper.java
new file mode 100644
index 00000000..23da8dd1
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/data/StudentMapper.java
@@ -0,0 +1,32 @@
+package com.xdc.basic.api.mybatis.generator.data;
+
+import com.xdc.basic.api.mybatis.generator.model.Student;
+import com.xdc.basic.api.mybatis.generator.model.StudentExample;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+
+public interface StudentMapper {
+ int countByExample(StudentExample example);
+
+ int deleteByExample(StudentExample example);
+
+ int deleteByPrimaryKey(Integer id);
+
+ int insert(Student record);
+
+ int insertSelective(Student record);
+
+ List selectByExample(StudentExample example);
+
+ Student selectByPrimaryKey(Integer id);
+
+ int updateByExampleSelective(@Param("record") Student record, @Param("example") StudentExample example);
+
+ int updateByExample(@Param("record") Student record, @Param("example") StudentExample example);
+
+ int updateByPrimaryKeySelective(Student record);
+
+ int updateByPrimaryKey(Student record);
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/data/StudentMapper.xml b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/data/StudentMapper.xml
new file mode 100644
index 00000000..20e8a577
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/data/StudentMapper.xml
@@ -0,0 +1,211 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+ id, name, gender, major, grade
+
+
+
+
+ delete from student
+ where id = #{id,jdbcType=INTEGER}
+
+
+ delete from student
+
+
+
+
+
+ insert into student (id, name, gender,
+ major, grade)
+ values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{gender,jdbcType=CHAR},
+ #{major,jdbcType=VARCHAR}, #{grade,jdbcType=CHAR})
+
+
+ insert into student
+
+
+ id,
+
+
+ name,
+
+
+ gender,
+
+
+ major,
+
+
+ grade,
+
+
+
+
+ #{id,jdbcType=INTEGER},
+
+
+ #{name,jdbcType=VARCHAR},
+
+
+ #{gender,jdbcType=CHAR},
+
+
+ #{major,jdbcType=VARCHAR},
+
+
+ #{grade,jdbcType=CHAR},
+
+
+
+
+
+ update student
+
+
+ id = #{record.id,jdbcType=INTEGER},
+
+
+ name = #{record.name,jdbcType=VARCHAR},
+
+
+ gender = #{record.gender,jdbcType=CHAR},
+
+
+ major = #{record.major,jdbcType=VARCHAR},
+
+
+ grade = #{record.grade,jdbcType=CHAR},
+
+
+
+
+
+
+
+ update student
+ set id = #{record.id,jdbcType=INTEGER},
+ name = #{record.name,jdbcType=VARCHAR},
+ gender = #{record.gender,jdbcType=CHAR},
+ major = #{record.major,jdbcType=VARCHAR},
+ grade = #{record.grade,jdbcType=CHAR}
+
+
+
+
+
+ update student
+
+
+ name = #{name,jdbcType=VARCHAR},
+
+
+ gender = #{gender,jdbcType=CHAR},
+
+
+ major = #{major,jdbcType=VARCHAR},
+
+
+ grade = #{grade,jdbcType=CHAR},
+
+
+ where id = #{id,jdbcType=INTEGER}
+
+
+ update student
+ set name = #{name,jdbcType=VARCHAR},
+ gender = #{gender,jdbcType=CHAR},
+ major = #{major,jdbcType=VARCHAR},
+ grade = #{grade,jdbcType=CHAR}
+ where id = #{id,jdbcType=INTEGER}
+
+
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/data/mybatis-config.xml b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/data/mybatis-config.xml
new file mode 100644
index 00000000..b5dc8b1b
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/data/mybatis-config.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/model/Student.java b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/model/Student.java
new file mode 100644
index 00000000..7eadd5a2
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/model/Student.java
@@ -0,0 +1,86 @@
+package com.xdc.basic.api.mybatis.generator.model;
+
+public class Student
+{
+ private Integer id;
+
+ private String name;
+
+ private String gender;
+
+ private String major;
+
+ private String grade;
+
+ public Student()
+ {
+ super();
+ }
+
+ public Student(Integer id, String name, String gender, String major, String grade)
+ {
+ super();
+ this.id = id;
+ this.name = name;
+ this.gender = gender;
+ this.major = major;
+ this.grade = grade;
+ }
+
+ public Integer getId()
+ {
+ return id;
+ }
+
+ public void setId(Integer id)
+ {
+ this.id = id;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name == null ? null : name.trim();
+ }
+
+ public String getGender()
+ {
+ return gender;
+ }
+
+ public void setGender(String gender)
+ {
+ this.gender = gender == null ? null : gender.trim();
+ }
+
+ public String getMajor()
+ {
+ return major;
+ }
+
+ public void setMajor(String major)
+ {
+ this.major = major == null ? null : major.trim();
+ }
+
+ public String getGrade()
+ {
+ return grade;
+ }
+
+ public void setGrade(String grade)
+ {
+ this.grade = grade == null ? null : grade.trim();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Student [id=" + id + ", name=" + name + ", gender=" + gender + ", major=" + major + ", grade=" + grade
+ + "]";
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/model/StudentExample.java b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/model/StudentExample.java
new file mode 100644
index 00000000..4503c428
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/model/StudentExample.java
@@ -0,0 +1,540 @@
+package com.xdc.basic.api.mybatis.generator.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StudentExample {
+ protected String orderByClause;
+
+ protected boolean distinct;
+
+ protected List oredCriteria;
+
+ public StudentExample() {
+ oredCriteria = new ArrayList();
+ }
+
+ public void setOrderByClause(String orderByClause) {
+ this.orderByClause = orderByClause;
+ }
+
+ public String getOrderByClause() {
+ return orderByClause;
+ }
+
+ public void setDistinct(boolean distinct) {
+ this.distinct = distinct;
+ }
+
+ public boolean isDistinct() {
+ return distinct;
+ }
+
+ public List getOredCriteria() {
+ return oredCriteria;
+ }
+
+ public void or(Criteria criteria) {
+ oredCriteria.add(criteria);
+ }
+
+ public Criteria or() {
+ Criteria criteria = createCriteriaInternal();
+ oredCriteria.add(criteria);
+ return criteria;
+ }
+
+ public Criteria createCriteria() {
+ Criteria criteria = createCriteriaInternal();
+ if (oredCriteria.size() == 0) {
+ oredCriteria.add(criteria);
+ }
+ return criteria;
+ }
+
+ protected Criteria createCriteriaInternal() {
+ Criteria criteria = new Criteria();
+ return criteria;
+ }
+
+ public void clear() {
+ oredCriteria.clear();
+ orderByClause = null;
+ distinct = false;
+ }
+
+ protected abstract static class GeneratedCriteria {
+ protected List criteria;
+
+ protected GeneratedCriteria() {
+ super();
+ criteria = new ArrayList();
+ }
+
+ public boolean isValid() {
+ return criteria.size() > 0;
+ }
+
+ public List getAllCriteria() {
+ return criteria;
+ }
+
+ public List getCriteria() {
+ return criteria;
+ }
+
+ protected void addCriterion(String condition) {
+ if (condition == null) {
+ throw new RuntimeException("Value for condition cannot be null");
+ }
+ criteria.add(new Criterion(condition));
+ }
+
+ protected void addCriterion(String condition, Object value, String property) {
+ if (value == null) {
+ throw new RuntimeException("Value for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value));
+ }
+
+ protected void addCriterion(String condition, Object value1, Object value2, String property) {
+ if (value1 == null || value2 == null) {
+ throw new RuntimeException("Between values for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value1, value2));
+ }
+
+ public Criteria andIdIsNull() {
+ addCriterion("id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIsNotNull() {
+ addCriterion("id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdEqualTo(Integer value) {
+ addCriterion("id =", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotEqualTo(Integer value) {
+ addCriterion("id <>", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThan(Integer value) {
+ addCriterion("id >", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThanOrEqualTo(Integer value) {
+ addCriterion("id >=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThan(Integer value) {
+ addCriterion("id <", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThanOrEqualTo(Integer value) {
+ addCriterion("id <=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIn(List values) {
+ addCriterion("id in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotIn(List values) {
+ addCriterion("id not in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdBetween(Integer value1, Integer value2) {
+ addCriterion("id between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotBetween(Integer value1, Integer value2) {
+ addCriterion("id not between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameIsNull() {
+ addCriterion("name is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameIsNotNull() {
+ addCriterion("name is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameEqualTo(String value) {
+ addCriterion("name =", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameNotEqualTo(String value) {
+ addCriterion("name <>", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameGreaterThan(String value) {
+ addCriterion("name >", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameGreaterThanOrEqualTo(String value) {
+ addCriterion("name >=", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameLessThan(String value) {
+ addCriterion("name <", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameLessThanOrEqualTo(String value) {
+ addCriterion("name <=", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameLike(String value) {
+ addCriterion("name like", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameNotLike(String value) {
+ addCriterion("name not like", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameIn(List values) {
+ addCriterion("name in", values, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameNotIn(List values) {
+ addCriterion("name not in", values, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameBetween(String value1, String value2) {
+ addCriterion("name between", value1, value2, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameNotBetween(String value1, String value2) {
+ addCriterion("name not between", value1, value2, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderIsNull() {
+ addCriterion("gender is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderIsNotNull() {
+ addCriterion("gender is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderEqualTo(String value) {
+ addCriterion("gender =", value, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderNotEqualTo(String value) {
+ addCriterion("gender <>", value, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderGreaterThan(String value) {
+ addCriterion("gender >", value, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderGreaterThanOrEqualTo(String value) {
+ addCriterion("gender >=", value, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderLessThan(String value) {
+ addCriterion("gender <", value, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderLessThanOrEqualTo(String value) {
+ addCriterion("gender <=", value, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderLike(String value) {
+ addCriterion("gender like", value, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderNotLike(String value) {
+ addCriterion("gender not like", value, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderIn(List values) {
+ addCriterion("gender in", values, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderNotIn(List values) {
+ addCriterion("gender not in", values, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderBetween(String value1, String value2) {
+ addCriterion("gender between", value1, value2, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andGenderNotBetween(String value1, String value2) {
+ addCriterion("gender not between", value1, value2, "gender");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorIsNull() {
+ addCriterion("major is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorIsNotNull() {
+ addCriterion("major is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorEqualTo(String value) {
+ addCriterion("major =", value, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorNotEqualTo(String value) {
+ addCriterion("major <>", value, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorGreaterThan(String value) {
+ addCriterion("major >", value, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorGreaterThanOrEqualTo(String value) {
+ addCriterion("major >=", value, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorLessThan(String value) {
+ addCriterion("major <", value, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorLessThanOrEqualTo(String value) {
+ addCriterion("major <=", value, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorLike(String value) {
+ addCriterion("major like", value, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorNotLike(String value) {
+ addCriterion("major not like", value, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorIn(List values) {
+ addCriterion("major in", values, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorNotIn(List values) {
+ addCriterion("major not in", values, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorBetween(String value1, String value2) {
+ addCriterion("major between", value1, value2, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andMajorNotBetween(String value1, String value2) {
+ addCriterion("major not between", value1, value2, "major");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeIsNull() {
+ addCriterion("grade is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeIsNotNull() {
+ addCriterion("grade is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeEqualTo(String value) {
+ addCriterion("grade =", value, "grade");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeNotEqualTo(String value) {
+ addCriterion("grade <>", value, "grade");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeGreaterThan(String value) {
+ addCriterion("grade >", value, "grade");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeGreaterThanOrEqualTo(String value) {
+ addCriterion("grade >=", value, "grade");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeLessThan(String value) {
+ addCriterion("grade <", value, "grade");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeLessThanOrEqualTo(String value) {
+ addCriterion("grade <=", value, "grade");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeLike(String value) {
+ addCriterion("grade like", value, "grade");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeNotLike(String value) {
+ addCriterion("grade not like", value, "grade");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeIn(List values) {
+ addCriterion("grade in", values, "grade");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeNotIn(List values) {
+ addCriterion("grade not in", values, "grade");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeBetween(String value1, String value2) {
+ addCriterion("grade between", value1, value2, "grade");
+ return (Criteria) this;
+ }
+
+ public Criteria andGradeNotBetween(String value1, String value2) {
+ addCriterion("grade not between", value1, value2, "grade");
+ return (Criteria) this;
+ }
+ }
+
+ public static class Criteria extends GeneratedCriteria {
+
+ protected Criteria() {
+ super();
+ }
+ }
+
+ public static class Criterion {
+ private String condition;
+
+ private Object value;
+
+ private Object secondValue;
+
+ private boolean noValue;
+
+ private boolean singleValue;
+
+ private boolean betweenValue;
+
+ private boolean listValue;
+
+ private String typeHandler;
+
+ public String getCondition() {
+ return condition;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Object getSecondValue() {
+ return secondValue;
+ }
+
+ public boolean isNoValue() {
+ return noValue;
+ }
+
+ public boolean isSingleValue() {
+ return singleValue;
+ }
+
+ public boolean isBetweenValue() {
+ return betweenValue;
+ }
+
+ public boolean isListValue() {
+ return listValue;
+ }
+
+ public String getTypeHandler() {
+ return typeHandler;
+ }
+
+ protected Criterion(String condition) {
+ super();
+ this.condition = condition;
+ this.typeHandler = null;
+ this.noValue = true;
+ }
+
+ protected Criterion(String condition, Object value, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.typeHandler = typeHandler;
+ if (value instanceof List>) {
+ this.listValue = true;
+ } else {
+ this.singleValue = true;
+ }
+ }
+
+ protected Criterion(String condition, Object value) {
+ this(condition, value, null);
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.secondValue = secondValue;
+ this.typeHandler = typeHandler;
+ this.betweenValue = true;
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue) {
+ this(condition, value, secondValue, null);
+ }
+ }
+}
\ No newline at end of file
diff --git "a/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/other/MyBatis Generator \344\273\243\347\240\201\347\224\237\346\210\220\345\267\245\345\205\267 -- \346\234\254\344\276\213\350\256\276\347\275\256.zip" "b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/other/MyBatis Generator \344\273\243\347\240\201\347\224\237\346\210\220\345\267\245\345\205\267 -- \346\234\254\344\276\213\350\256\276\347\275\256.zip"
new file mode 100644
index 00000000..b6cdee3e
Binary files /dev/null and "b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/other/MyBatis Generator \344\273\243\347\240\201\347\224\237\346\210\220\345\267\245\345\205\267 -- \346\234\254\344\276\213\350\256\276\347\275\256.zip" differ
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/other/student_mysql.sql b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/other/student_mysql.sql
new file mode 100644
index 00000000..0816d066
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/other/student_mysql.sql
@@ -0,0 +1,25 @@
+/*创建college数据库*/
+drop database if exists college;
+create database college;
+
+/*切换到college数据库*/
+use college;
+
+/*创建学生表*/
+CREATE TABLE student(
+ id int NOT NULL AUTO_INCREMENT primary key,
+ name varchar(10) NOT NULL,/*姓名*/
+ gender char(1) NOT NULL,/*性别*/
+ major varchar(20) NOT NULL,/*专业*/
+ grade char(4) NOT NULL/*年级*/
+);
+
+/*授予college用户访问college数据库的全部权限。为方便起见,用户名与数据库同名。
+该用户若不存在则被创建,密码为123456*/
+grant all privileges on college.* to college@'%' identified by '123456';
+flush privileges;
+
+/*添加记录*/
+insert into student(name, gender, major, grade)values('徐大超','男','计算机科学与技术','2008');
+insert into student(name, gender, major, grade)values('王梓维','男','计算机科学与技术','2008');
+insert into student(name, gender, major, grade)values('陈冲','女','计算机科学与技术','2008');
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/other/student_oracle.sql b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/other/student_oracle.sql
new file mode 100644
index 00000000..7a42811a
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/generator/other/student_oracle.sql
@@ -0,0 +1,15 @@
+/*在system用户下执行*/
+
+/*添加记录*/
+CREATE TABLE student(
+ id int NOT NULL primary key,
+ name varchar(20) NOT NULL,/*姓名*/
+ gender char(10) NOT NULL,/*性别*/
+ major varchar(50) NOT NULL,/*专业*/
+ grade char(4) NOT NULL/*年级*/
+);
+
+/*添加记录*/
+insert into student(id, name, gender, major, grade)values('1','徐大超','男','计算机科学与技术','2008');
+insert into student(id, name, gender, major, grade)values('2','王梓维','男','计算机科学与技术','2008');
+insert into student(id, name, gender, major, grade)values('3','陈冲','女','计算机科学与技术','2008');
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/MyBatisTest.java b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/MyBatisTest.java
new file mode 100644
index 00000000..96fa9687
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/MyBatisTest.java
@@ -0,0 +1,64 @@
+package com.xdc.basic.api.mybatis.manual;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.session.SqlSessionFactoryBuilder;
+
+import com.xdc.basic.api.mybatis.manual.data.StudentMapper;
+import com.xdc.basic.api.mybatis.manual.model.Student;
+
+public class MyBatisTest
+{
+ public static void main(String[] args) throws IOException
+ {
+ String resource = "com/xdc/basic/example/mybatis/manual/data/mybatis-config.xml";
+ Reader reader = Resources.getResourceAsReader(resource);
+
+ SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
+
+ /*
+ * http://mybatis.github.io/mybatis-3/zh/java-api.html#sqlSessions
+ * 默认的 openSession()方法没有参数,它会创建有如下特性的 SqlSession:
+ * 1.会开启一个事务(也就是不自动提交)。
+ * 2.连接对象会从由活动环境配置的数据源实例中得到。
+ * 3.事务隔离级别将会使用驱动或数据源的默认设置。
+ * 4.预处理语句不会被复用,也不会批量处理更新。
+ */
+ SqlSession sqlSession = sqlSessionFactory.openSession();
+
+ try
+ {
+ StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
+
+ Student student = studentMapper.selectByPrimaryKey(4);
+ System.out.println("插入前:" + student);
+
+ studentMapper.insert(new Student(4, "耿雪", "女", "计算机科学与技术", "2008"));
+
+ student = studentMapper.selectByPrimaryKey(4);
+ System.out.println("提交前:" + student);
+
+ // 提交的意义在于:在其他的sqlSession中能够看见语句的结果,而在本身的sqlSession中,无论提交与否,都是可见的。
+ sqlSession.commit();
+
+ student = studentMapper.selectByPrimaryKey(4);
+ System.out.println("提交后:" + student);
+
+ studentMapper.deleteByPrimaryKey(4);
+
+ sqlSession.commit();
+
+ student = studentMapper.selectByPrimaryKey(4);
+ System.out.println("删除后:" + student);
+ }
+ finally
+ {
+ // 如果在关闭前都没有提交,那么前面的内容将自动回滚。
+ sqlSession.close();
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/data/StudentMapper.java b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/data/StudentMapper.java
new file mode 100644
index 00000000..1bea2409
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/data/StudentMapper.java
@@ -0,0 +1,14 @@
+package com.xdc.basic.api.mybatis.manual.data;
+
+import com.xdc.basic.api.mybatis.manual.model.Student;
+
+public interface StudentMapper
+{
+ int insert(Student record);
+
+ int deleteByPrimaryKey(Integer id);
+
+ Student selectByPrimaryKey(Integer id);
+
+ int updateByPrimaryKey(Student record);
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/data/StudentMapper.xml b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/data/StudentMapper.xml
new file mode 100644
index 00000000..c8562e36
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/data/StudentMapper.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+ insert into
+ student (id, name, gender, major, grade)
+ values
+ (#{id}, #{name}, #{gender}, #{major}, #{grade})
+
+
+
+ delete from
+ student
+ where id = #{id}
+
+
+
+ update
+ student
+ set
+ name = #{name},
+ gender = #{gender},
+ major = #{major},
+ grade = #{grade}
+ where id = #{id}
+
+
+
+
+
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/data/mybatis-config.xml b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/data/mybatis-config.xml
new file mode 100644
index 00000000..b52e77b0
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/data/mybatis-config.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/model/Student.java b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/model/Student.java
new file mode 100644
index 00000000..2541b673
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/model/Student.java
@@ -0,0 +1,86 @@
+package com.xdc.basic.api.mybatis.manual.model;
+
+public class Student
+{
+ private Integer id;
+
+ private String name;
+
+ private String gender;
+
+ private String major;
+
+ private String grade;
+
+ public Student()
+ {
+ super();
+ }
+
+ public Student(Integer id, String name, String gender, String major, String grade)
+ {
+ super();
+ this.id = id;
+ this.name = name;
+ this.gender = gender;
+ this.major = major;
+ this.grade = grade;
+ }
+
+ public Integer getId()
+ {
+ return id;
+ }
+
+ public void setId(Integer id)
+ {
+ this.id = id;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name == null ? null : name.trim();
+ }
+
+ public String getGender()
+ {
+ return gender;
+ }
+
+ public void setGender(String gender)
+ {
+ this.gender = gender == null ? null : gender.trim();
+ }
+
+ public String getMajor()
+ {
+ return major;
+ }
+
+ public void setMajor(String major)
+ {
+ this.major = major == null ? null : major.trim();
+ }
+
+ public String getGrade()
+ {
+ return grade;
+ }
+
+ public void setGrade(String grade)
+ {
+ this.grade = grade == null ? null : grade.trim();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Student [id=" + id + ", name=" + name + ", gender=" + gender + ", major=" + major + ", grade=" + grade
+ + "]";
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/other/student_mysql.sql b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/other/student_mysql.sql
new file mode 100644
index 00000000..0816d066
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/other/student_mysql.sql
@@ -0,0 +1,25 @@
+/*创建college数据库*/
+drop database if exists college;
+create database college;
+
+/*切换到college数据库*/
+use college;
+
+/*创建学生表*/
+CREATE TABLE student(
+ id int NOT NULL AUTO_INCREMENT primary key,
+ name varchar(10) NOT NULL,/*姓名*/
+ gender char(1) NOT NULL,/*性别*/
+ major varchar(20) NOT NULL,/*专业*/
+ grade char(4) NOT NULL/*年级*/
+);
+
+/*授予college用户访问college数据库的全部权限。为方便起见,用户名与数据库同名。
+该用户若不存在则被创建,密码为123456*/
+grant all privileges on college.* to college@'%' identified by '123456';
+flush privileges;
+
+/*添加记录*/
+insert into student(name, gender, major, grade)values('徐大超','男','计算机科学与技术','2008');
+insert into student(name, gender, major, grade)values('王梓维','男','计算机科学与技术','2008');
+insert into student(name, gender, major, grade)values('陈冲','女','计算机科学与技术','2008');
diff --git a/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/other/student_oracle.sql b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/other/student_oracle.sql
new file mode 100644
index 00000000..7a42811a
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/mybatis/manual/other/student_oracle.sql
@@ -0,0 +1,15 @@
+/*在system用户下执行*/
+
+/*添加记录*/
+CREATE TABLE student(
+ id int NOT NULL primary key,
+ name varchar(20) NOT NULL,/*姓名*/
+ gender char(10) NOT NULL,/*性别*/
+ major varchar(50) NOT NULL,/*专业*/
+ grade char(4) NOT NULL/*年级*/
+);
+
+/*添加记录*/
+insert into student(id, name, gender, major, grade)values('1','徐大超','男','计算机科学与技术','2008');
+insert into student(id, name, gender, major, grade)values('2','王梓维','男','计算机科学与技术','2008');
+insert into student(id, name, gender, major, grade)values('3','陈冲','女','计算机科学与技术','2008');
diff --git a/basicKnowledge/src/com/xdc/basic/api/nio/CopyFile.java b/basicKnowledge/src/com/xdc/basic/api/nio/CopyFile.java
new file mode 100644
index 00000000..e0344fc0
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/nio/CopyFile.java
@@ -0,0 +1,46 @@
+package com.xdc.basic.api.nio;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+public class CopyFile
+{
+ @SuppressWarnings("resource")
+ static public void main(String args[]) throws Exception
+ {
+ if (args.length < 2)
+ {
+ System.err.println("Usage: java CopyFile infile outfile");
+ System.exit(1);
+ }
+
+ String infile = args[0];
+ String outfile = args[1];
+
+ FileInputStream fin = new FileInputStream(infile);
+ FileOutputStream fout = new FileOutputStream(outfile);
+
+ FileChannel fcin = fin.getChannel();
+ FileChannel fcout = fout.getChannel();
+
+ ByteBuffer buffer = ByteBuffer.allocate(1024);
+
+ while (true)
+ {
+ buffer.clear();
+
+ int r = fcin.read(buffer);
+
+ if (r == -1)
+ {
+ break;
+ }
+
+ buffer.flip();
+
+ fcout.write(buffer);
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/nio/ReadAndShow.java b/basicKnowledge/src/com/xdc/basic/api/nio/ReadAndShow.java
new file mode 100644
index 00000000..a6e9b8b2
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/nio/ReadAndShow.java
@@ -0,0 +1,30 @@
+package com.xdc.basic.api.nio;
+
+import java.io.FileInputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+public class ReadAndShow
+{
+ static public void main(String args[]) throws Exception
+ {
+ FileInputStream fin = new FileInputStream("readandshow.txt");
+ FileChannel fc = fin.getChannel();
+
+ ByteBuffer buffer = ByteBuffer.allocate(1024);
+
+ fc.read(buffer);
+
+ buffer.flip();
+
+ int i = 0;
+ while (buffer.remaining() > 0)
+ {
+ byte b = buffer.get();
+ System.out.println("Character " + i + ": " + ((char) b));
+ i++;
+ }
+
+ fin.close();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/ReflectionTest.java b/basicKnowledge/src/com/xdc/basic/api/reflection/ReflectionTest.java
new file mode 100644
index 00000000..5c2182b7
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/ReflectionTest.java
@@ -0,0 +1,140 @@
+package com.xdc.basic.api.reflection;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.junit.Test;
+
+public class ReflectionTest
+{
+ /**
+ * 反射基本样例
+ */
+ @Test
+ public void reflectionDemo()
+ {
+ // 在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:
+ // Class类:代表一个类。
+ // Field类:代表类的成员变量(成员变量也称为类的属性)。
+ // Method类:代表类的方法。
+ // Constructor类:代表类的构造方法。
+ // Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
+
+ // 要想使用反射,首先需要获得待处理类或对象所对应的Class对象。
+ // 获取某个类或某个对象所对应的class对象的常用的3种方式:
+ // 1. 使用Class类的静态方法forName:Class.forName(“java.lang.String”);
+ // 2. 使用类的.class语法:String.class;
+ // 3. 使用对象的getClass()方法:String s = “abc”; Class> clazz = s.getClass();
+
+ // Class类是Reflection API中的核心类,它有以下方法
+ // getName():获得类的完整名字。
+ // getFields():获得类的public类型的属性。
+ // getDeclaredFields():获得类的所有属性。
+ // getMethods():获得类的public类型的方法。
+ // getDeclaredMethods():获得类的所有方法。
+ // getMethod(String name,Class[]parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。
+ // getConstructors():获得类的public类型的构造方法。
+ // getDeclaredConstructors:获得类的所有构造方法。
+ // getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。
+ // newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
+
+ Class clazz = Student.class;
+
+ String name = clazz.getName();
+ System.out.println(name);
+
+ Field[] fields = clazz.getFields();
+ System.out.println(ArrayUtils.toString(fields));
+
+ Field[] declaredFields = clazz.getDeclaredFields();
+ System.out.println(ArrayUtils.toString(declaredFields));
+
+ Method[] methods = clazz.getMethods();
+ System.out.println(ArrayUtils.toString(methods));
+
+ Method[] declaredMethods = clazz.getDeclaredMethods();
+ System.out.println(ArrayUtils.toString(declaredMethods));
+
+ Constructor>[] constructors = clazz.getConstructors();
+ System.out.println(ArrayUtils.toString(constructors));
+
+ Constructor>[] declaredConstructors = clazz.getDeclaredConstructors();
+ System.out.println(ArrayUtils.toString(declaredConstructors));
+ }
+
+ /**
+ * 调用私有方法
+ *
+ * @throws NoSuchMethodException
+ * @throws SecurityException
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ * @throws IllegalArgumentException
+ * @throws InvocationTargetException
+ */
+ @Test
+ public void invokePrivateMethod() throws NoSuchMethodException, SecurityException, InstantiationException,
+ IllegalAccessException, IllegalArgumentException, InvocationTargetException
+ {
+ Class clazz = Student.class;
+
+ Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
+ constructor.setAccessible(true);
+ Student student = constructor.newInstance("xudachao", 25);
+ System.out.println(student);
+
+ Method method = clazz.getDeclaredMethod("eat", String.class);
+ method.setAccessible(true);
+ method.invoke(student, "egg");
+ }
+
+ /**
+ * 修改私有属性(即使没有set和get方法)
+ *
+ * @throws InvocationTargetException
+ * @throws IllegalArgumentException
+ * @throws IllegalAccessException
+ * @throws InstantiationException
+ * @throws SecurityException
+ * @throws NoSuchMethodException
+ * @throws NoSuchFieldException
+ */
+ @Test
+ public void modifyPrivateField() throws InstantiationException, IllegalAccessException, IllegalArgumentException,
+ InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException
+ {
+ Class clazz = Student.class;
+
+ Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
+ constructor.setAccessible(true);
+ Student student = constructor.newInstance("xudachao", 25);
+ System.out.println(student);
+
+ Field ageField = clazz.getDeclaredField("age");
+ ageField.setAccessible(true);
+ ageField.set(student, 26);
+ System.out.println(student);
+ }
+
+ /**
+ * 一个类对应的class对象只会加载一次
+ *
+ * @throws ClassNotFoundException
+ */
+ @Test
+ public void ClassLoaderTest() throws ClassNotFoundException
+ {
+ Class c1 = String.class;
+
+ Class> c2 = Class.forName("java.lang.String");
+
+ String str = "Just do it.";
+ Class> c3 = str.getClass();
+
+ System.out.println(c1 == c2);
+ System.out.println(c1 == c3);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/Student.java b/basicKnowledge/src/com/xdc/basic/api/reflection/Student.java
new file mode 100644
index 00000000..506e5c09
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/Student.java
@@ -0,0 +1,47 @@
+package com.xdc.basic.api.reflection;
+
+public class Student
+{
+ public String name;
+ private int age;
+
+ public Student()
+ {
+ super();
+ }
+
+ @SuppressWarnings("unused")
+ private Student(String name, int age)
+ {
+ super();
+ this.name = name;
+ this.age = age;
+ }
+
+ public int getAge()
+ {
+ return age;
+ }
+
+ public void setAge(int age)
+ {
+ this.age = age;
+ }
+
+ public void study()
+ {
+ System.out.println("I study all day and night.");
+ }
+
+ @SuppressWarnings("unused")
+ private void eat(String food)
+ {
+ System.out.println("I'm eating " + food + ". I'm a foodie.");
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Student [name=" + name + ", age=" + age + "]";
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/AnnotationTest.java b/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/AnnotationTest.java
new file mode 100644
index 00000000..30445b08
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/AnnotationTest.java
@@ -0,0 +1,46 @@
+package com.xdc.basic.api.reflection.annotation;
+
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * http://blog.csdn.net/sooneasy/article/details/4384888
+ *
+ * @author xdc
+ *
+ */
+public class AnnotationTest
+{
+ /**
+ * author lighter 说明:具体关天Annotation的API的用法请参见javaDoc文档
+ */
+ public static void main(String[] args) throws Exception
+ {
+ String CLASS_NAME = "com.xdc.basic.apidemo.annotation.JavaEyer";
+ Class> test = Class.forName(CLASS_NAME);
+ Method[] method = test.getMethods();
+ boolean flag = test.isAnnotationPresent(Description.class);
+ if (flag)
+ {
+ Description des = (Description) test.getAnnotation(Description.class);
+ System.out.println("描述:" + des.value());
+ System.out.println("-----------------");
+ }
+
+ // 把JavaEyer这一类有利用到@Name的全部方法保存到Set中去
+ Set set = new HashSet();
+ for (int i = 0; i < method.length; i++)
+ {
+ boolean otherFlag = method[i].isAnnotationPresent(Name.class);
+ if (otherFlag)
+ set.add(method[i]);
+ }
+ for (Method m : set)
+ {
+ Name name = m.getAnnotation(Name.class);
+ System.out.println(name.originate());
+ System.out.println("创建的社区:" + name.community());
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/Description.java b/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/Description.java
new file mode 100644
index 00000000..5cbcca98
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/Description.java
@@ -0,0 +1,15 @@
+package com.xdc.basic.api.reflection.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Description
+{
+ String value();
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/JavaEyer.java b/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/JavaEyer.java
new file mode 100644
index 00000000..17495b74
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/JavaEyer.java
@@ -0,0 +1,17 @@
+package com.xdc.basic.api.reflection.annotation;
+
+@Description("javaeye,做最棒的软件开发交流社区")
+public class JavaEyer
+{
+ @Name(originate = "创始人:robbin", community = "javaEye")
+ public String getName()
+ {
+ return null;
+ }
+
+ @Name(originate = "创始人:江南白衣", community = "springside")
+ public String getName2()
+ {
+ return "借用两位的id一用,写这一个例子,请见谅!";
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/Name.java b/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/Name.java
new file mode 100644
index 00000000..79899960
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/annotation/Name.java
@@ -0,0 +1,18 @@
+package com.xdc.basic.api.reflection.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+//注意这里的@Target与Description里的不同,参数成员也不同
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Name
+{
+ String originate();
+
+ String community();
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessBar.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessBar.java
new file mode 100644
index 00000000..00ab3d20
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessBar.java
@@ -0,0 +1,6 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxycglib;
+
+public interface BusinessBar
+{
+ String bar(String message);
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessBarImpl.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessBarImpl.java
new file mode 100644
index 00000000..5098d41b
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessBarImpl.java
@@ -0,0 +1,10 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxycglib;
+
+public class BusinessBarImpl implements BusinessBar
+{
+ public String bar(String message)
+ {
+ System.out.println("BusinessBarImpl.bar()");
+ return message;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessFoo.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessFoo.java
new file mode 100644
index 00000000..60c2b385
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessFoo.java
@@ -0,0 +1,6 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxycglib;
+
+public interface BusinessFoo
+{
+ void foo();
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessFooImpl.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessFooImpl.java
new file mode 100644
index 00000000..d8c50801
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessFooImpl.java
@@ -0,0 +1,9 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxycglib;
+
+public class BusinessFooImpl implements BusinessFoo
+{
+ public void foo()
+ {
+ System.out.println("BusinessFooImpl.foo()");
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessImplCglibProxy.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessImplCglibProxy.java
new file mode 100644
index 00000000..db0c1111
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/BusinessImplCglibProxy.java
@@ -0,0 +1,39 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxycglib;
+
+import java.lang.reflect.Method;
+
+import org.springframework.cglib.proxy.Enhancer;
+import org.springframework.cglib.proxy.MethodInterceptor;
+import org.springframework.cglib.proxy.MethodProxy;
+
+class BusinessImplCglibProxy implements MethodInterceptor
+{
+ @Override
+ public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable
+ {
+ doBefore();
+ Object result = proxy.invokeSuper(obj, args);
+ doAfter();
+ return result;
+ }
+
+ private void doBefore()
+ {
+ System.out.println("前置处理!");
+ }
+
+ private void doAfter()
+ {
+ System.out.println("后置处理!");
+ }
+
+ public static Object factory(Class> clazz)
+ {
+ Enhancer enhancer = new Enhancer();
+ enhancer.setSuperclass(clazz);
+ // 回调方法
+ enhancer.setCallback(new BusinessImplCglibProxy());
+ // 创建代理对象
+ return enhancer.create();
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/DynamicProxyTest.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/DynamicProxyTest.java
new file mode 100644
index 00000000..b3f118e6
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxycglib/DynamicProxyTest.java
@@ -0,0 +1,16 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxycglib;
+
+public class DynamicProxyTest
+{
+ public static void main(String[] args)
+ {
+ // 不依赖接口,也无需创建BusinessFooImpl实例,cglib自动创建BusinessFooImpl的子类的实例
+ BusinessFooImpl bf = (BusinessFooImpl) BusinessImplCglibProxy.factory(BusinessFooImpl.class);
+ bf.foo();
+ System.out.println();
+
+ BusinessBarImpl bb = (BusinessBarImpl) BusinessImplCglibProxy.factory(BusinessBarImpl.class);
+ String message = bb.bar("Hello,World");
+ System.out.println(message);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessBar.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessBar.java
new file mode 100644
index 00000000..5f78444d
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessBar.java
@@ -0,0 +1,6 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxyjdk;
+
+public interface BusinessBar
+{
+ String bar(String message);
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessBarImpl.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessBarImpl.java
new file mode 100644
index 00000000..6cbf0b70
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessBarImpl.java
@@ -0,0 +1,10 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxyjdk;
+
+public class BusinessBarImpl implements BusinessBar
+{
+ public String bar(String message)
+ {
+ System.out.println("BusinessBarImpl.bar()");
+ return message;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessFoo.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessFoo.java
new file mode 100644
index 00000000..f58aeabe
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessFoo.java
@@ -0,0 +1,6 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxyjdk;
+
+public interface BusinessFoo
+{
+ void foo();
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessFooImpl.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessFooImpl.java
new file mode 100644
index 00000000..a4b9b2e3
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessFooImpl.java
@@ -0,0 +1,9 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxyjdk;
+
+public class BusinessFooImpl implements BusinessFoo
+{
+ public void foo()
+ {
+ System.out.println("BusinessFooImpl.foo()");
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessImplJdkProxy.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessImplJdkProxy.java
new file mode 100644
index 00000000..1243e6ed
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/BusinessImplJdkProxy.java
@@ -0,0 +1,49 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxyjdk;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+class BusinessImplJdkProxy implements InvocationHandler
+{
+ private Object targetObject;
+
+ public BusinessImplJdkProxy()
+ {
+ super();
+ }
+
+ public BusinessImplJdkProxy(Object obj)
+ {
+ super();
+ this.targetObject = obj;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+ {
+ doBefore();
+ Object result = method.invoke(targetObject, args);
+ doAfter();
+ return result;
+ }
+
+ private void doBefore()
+ {
+ System.out.println("前置处理!");
+ }
+
+ private void doAfter()
+ {
+ System.out.println("后置处理!");
+ }
+
+ public static Object factory(Object obj)
+ {
+ Class> clazz = obj.getClass();
+ ClassLoader classLoader = clazz.getClassLoader();
+ Class>[] interfaces = clazz.getInterfaces();
+
+ //取得代理对象, 要绑定接口(这是jdk动态代理的一个缺陷,cglib动态代理弥补了这一缺陷)
+ return Proxy.newProxyInstance(classLoader, interfaces, new BusinessImplJdkProxy(obj));
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/DynamicProxyTest.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/DynamicProxyTest.java
new file mode 100644
index 00000000..c15fd85a
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/dynamicproxyjdk/DynamicProxyTest.java
@@ -0,0 +1,17 @@
+package com.xdc.basic.api.reflection.proxy.comparison.dynamicproxyjdk;
+
+public class DynamicProxyTest
+{
+ public static void main(String[] args)
+ {
+ BusinessFooImpl bfoo = new BusinessFooImpl();
+ BusinessFoo bf = (BusinessFoo) BusinessImplJdkProxy.factory(bfoo);
+ bf.foo();
+ System.out.println();
+
+ BusinessBarImpl bbar = new BusinessBarImpl();
+ BusinessBar bb = (BusinessBar) BusinessImplJdkProxy.factory(bbar);
+ String message = bb.bar("Hello,World");
+ System.out.println(message);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/Business.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/Business.java
new file mode 100644
index 00000000..363db0e8
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/Business.java
@@ -0,0 +1,8 @@
+package com.xdc.basic.api.reflection.proxy.comparison.staticproxy;
+
+public interface Business
+{
+ void doAction();
+
+ void doAction2();
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/BusinessImpl.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/BusinessImpl.java
new file mode 100644
index 00000000..ae4ef052
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/BusinessImpl.java
@@ -0,0 +1,16 @@
+package com.xdc.basic.api.reflection.proxy.comparison.staticproxy;
+
+public class BusinessImpl implements Business
+{
+ @Override
+ public void doAction()
+ {
+ System.out.println("do action.");
+ }
+
+ @Override
+ public void doAction2()
+ {
+ System.out.println("do action2.");
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/BusinessImplProxy.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/BusinessImplProxy.java
new file mode 100644
index 00000000..1042c46a
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/BusinessImplProxy.java
@@ -0,0 +1,54 @@
+package com.xdc.basic.api.reflection.proxy.comparison.staticproxy;
+
+class BusinessImplProxy implements Business
+{
+ private BusinessImpl businessImpl;
+
+ public BusinessImplProxy()
+ {
+ super();
+ }
+
+ public BusinessImplProxy(BusinessImpl businessImpl)
+ {
+ super();
+ this.businessImpl = businessImpl;
+ }
+
+ @Override
+ public void doAction()
+ {
+ if (businessImpl == null)
+ {
+ businessImpl = new BusinessImpl();
+ }
+
+ doBefore();
+ businessImpl.doAction();
+ doAfter();
+ }
+
+ @Override
+ public void doAction2()
+ {
+ if (businessImpl == null)
+ {
+ businessImpl = new BusinessImpl();
+ }
+
+ doBefore();
+ businessImpl.doAction2();
+ doAfter();
+
+ }
+
+ private void doBefore()
+ {
+ System.out.println("前置处理!");
+ }
+
+ private void doAfter()
+ {
+ System.out.println("后置处理!");
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/StaticProxyTest.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/StaticProxyTest.java
new file mode 100644
index 00000000..6309e734
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/comparison/staticproxy/StaticProxyTest.java
@@ -0,0 +1,12 @@
+package com.xdc.basic.api.reflection.proxy.comparison.staticproxy;
+
+public class StaticProxyTest
+{
+ public static void main(String[] args)
+ {
+ BusinessImpl businessImpl = new BusinessImpl();
+ BusinessImplProxy businessImplProxy = new BusinessImplProxy(businessImpl);
+ businessImplProxy.doAction();
+ businessImplProxy.doAction2();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/After.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/After.java
new file mode 100644
index 00000000..cd3cdba3
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/After.java
@@ -0,0 +1,9 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo1;
+
+/**
+ * 后置增强接口
+ */
+public interface After
+{
+ public void after();
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/AopTest.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/AopTest.java
new file mode 100644
index 00000000..ca16cf19
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/AopTest.java
@@ -0,0 +1,53 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo1;
+
+public class AopTest
+{
+ public static void main(String[] args)
+ {
+ Before before = new Before()
+ {
+ public void before()
+ {
+ System.out.println("...before...");
+ }
+ };
+
+ After after = new After()
+ {
+ public void after()
+ {
+ System.out.println("...after...");
+ }
+ };
+
+ Hello hello = null;
+
+ // 普通方法执行
+ System.out.println("-------------普通执行-------------");
+ hello = new HelloEnglish();
+ hello.sayHello("bao110908");
+ hello.sayHi("bao110908");
+ System.out.println();
+
+ // 切入方法执行前(前置增强)
+ System.out.println("-------------前置增强-------------");
+ hello = HelloAopManager.getHelloProxy(new HelloEnglish(), before);
+ hello.sayHello("bao110908");
+ hello.sayHi("bao110908"); // sayHi 方法没有标注 @Enhancement 所以不会进行代码切入
+ System.out.println();
+
+ // 切入方法执行后(后置增强)
+ System.out.println("-------------后置增强-------------");
+ hello = HelloAopManager.getHelloProxy(new HelloEnglish(), after);
+ hello.sayHello("bao110908");
+ hello.sayHi("bao110908");
+ System.out.println();
+
+ // 切入方法执行前和执行后(环绕增强)
+ System.out.println("-------------环绕增强-------------");
+ hello = HelloAopManager.getHelloProxy(new HelloEnglish(), before, after);
+ hello.sayHello("bao110908");
+ hello.sayHi("bao110908");
+ System.out.println();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/Before.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/Before.java
new file mode 100644
index 00000000..9e0a26ae
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/Before.java
@@ -0,0 +1,9 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo1;
+
+/**
+ * 前置增强接口
+ */
+public interface Before
+{
+ public void before();
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/Enhancement.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/Enhancement.java
new file mode 100644
index 00000000..941777b9
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/Enhancement.java
@@ -0,0 +1,16 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo1;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * 有此注解的方法,才需要被增强
+ *
+ * @author xdc
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Enhancement
+{
+
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/Hello.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/Hello.java
new file mode 100644
index 00000000..3c636ff3
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/Hello.java
@@ -0,0 +1,9 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo1;
+
+public interface Hello
+{
+ @Enhancement
+ public void sayHello(String name);
+
+ public void sayHi(String name);
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloAopManager.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloAopManager.java
new file mode 100644
index 00000000..f1cb006a
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloAopManager.java
@@ -0,0 +1,32 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo1;
+
+public class HelloAopManager
+{
+ private HelloAopManager()
+ {
+ }
+
+ public static Hello getHelloProxy(Hello hello, Before before)
+ {
+ return getHelloProxy(hello, before, null);
+ }
+
+ public static Hello getHelloProxy(Hello hello, After after)
+ {
+ return getHelloProxy(hello, null, after);
+ }
+
+ public static Hello getHelloProxy(Hello hello, Before before, After after)
+ {
+ HelloHandler handler = new HelloHandler();
+ if (before != null)
+ {
+ handler.setBefore(before);
+ }
+ if (after != null)
+ {
+ handler.setAfter(after);
+ }
+ return handler.bind(hello);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloChinese.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloChinese.java
new file mode 100644
index 00000000..f8a97ba5
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloChinese.java
@@ -0,0 +1,14 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo1;
+
+public class HelloChinese implements Hello
+{
+ public void sayHello(String name)
+ {
+ System.out.println(name + ",您好");
+ }
+
+ public void sayHi(String name)
+ {
+ System.out.println("哈啰," + name);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloEnglish.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloEnglish.java
new file mode 100644
index 00000000..3cf55785
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloEnglish.java
@@ -0,0 +1,14 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo1;
+
+public class HelloEnglish implements Hello
+{
+ public void sayHello(String name)
+ {
+ System.out.println("Hello, " + name);
+ }
+
+ public void sayHi(String name)
+ {
+ System.out.println("hi, " + name);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloHandler.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloHandler.java
new file mode 100644
index 00000000..406928e8
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo1/HelloHandler.java
@@ -0,0 +1,75 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo1;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+public class HelloHandler implements InvocationHandler
+{
+ /**
+ * 需要进行代理的实例
+ */
+ private Hello hello = null;
+
+ /**
+ * 前置增强
+ */
+ private Before before = null;
+
+ /**
+ * 后置增强
+ */
+ private After after = null;
+
+ /**
+ * InvocationHandler 接口的实现方法,进行动态代理
+ */
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+ {
+ // 看看接口中方法是否标注了需要 Enhancement, 有的话需要增强
+ boolean needEnhancement = method.isAnnotationPresent(Enhancement.class);
+ if (!needEnhancement)
+ {
+ // 没有标注的话,按原方法执行
+ return method.invoke(hello, args);
+ }
+
+ // 有标注的话,进行方法的前置和后置增强
+ if (before != null)
+ {
+ before.before();
+ }
+ Object obj = method.invoke(hello, args);
+ if (after != null)
+ {
+ after.after();
+ }
+
+ return obj;
+ }
+
+ /**
+ * 将传入的 Hello 与 InvocationHandler 进行绑定,以获得代理类的实例
+ *
+ * @param hello
+ * @return
+ */
+ public Hello bind(Hello hello)
+ {
+ this.hello = hello;
+ Hello helloProxy = (Hello) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass()
+ .getInterfaces(), this);
+ return helloProxy;
+ }
+
+ public void setAfter(After after)
+ {
+ this.after = after;
+ }
+
+ public void setBefore(Before before)
+ {
+ this.before = before;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/AOPTest.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/AOPTest.java
new file mode 100644
index 00000000..3166d04f
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/AOPTest.java
@@ -0,0 +1,18 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo2;
+
+public class AOPTest
+{
+ public static void main(String[] args)
+ {
+ // 使用Proxy类实现:
+ // 1. 拦截所有业务方法
+ // 2. 判断用户是否有权限,有权限就允许他执行业务方法,没有权限不允许他执行业务方法(是否有权限是根据user是否为null作为判断依据)
+ JDKProxyFactory factory = new JDKProxyFactory();
+
+ BankService service = (BankService) factory.createProxyInstance(new BankServiceImpl());
+ service.payMoneyInto(100);
+
+ BankService servicewithUser = (BankService) factory.createProxyInstance(new BankServiceImpl("xudachao"));
+ servicewithUser.payMoneyInto(100);
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/BankService.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/BankService.java
new file mode 100644
index 00000000..c93a529a
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/BankService.java
@@ -0,0 +1,18 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo2;
+
+public interface BankService
+{
+ /**
+ * 存钱
+ *
+ * @param money
+ */
+ void payMoneyInto(int money);
+
+ /**
+ * 取钱
+ *
+ * @param money
+ */
+ void drawMoneyOut(int money);
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/BankServiceImpl.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/BankServiceImpl.java
new file mode 100644
index 00000000..f7e6bc75
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/BankServiceImpl.java
@@ -0,0 +1,32 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo2;
+
+public class BankServiceImpl implements BankService
+{
+ private String user = null;
+
+ public BankServiceImpl()
+ {
+ }
+
+ public BankServiceImpl(String user)
+ {
+ this.user = user;
+ }
+
+ public String getUser()
+ {
+ return user;
+ }
+
+ @Override
+ public void payMoneyInto(int money)
+ {
+ System.out.println("存入:" + money + "元.");
+ }
+
+ @Override
+ public void drawMoneyOut(int money)
+ {
+ System.out.println("取出:" + money + "元.");
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/JDKProxyFactory.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/JDKProxyFactory.java
new file mode 100644
index 00000000..916ec1e0
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/aop/demo2/JDKProxyFactory.java
@@ -0,0 +1,34 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.aop.demo2;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+public class JDKProxyFactory implements InvocationHandler
+{
+ private Object targetObject;
+
+ public Object createProxyInstance(Object targetObject)
+ {
+ this.targetObject = targetObject;
+ return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
+ targetObject.getClass().getInterfaces(), this);
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+ {
+ BankServiceImpl bankServiceImpl = (BankServiceImpl) targetObject;
+ Object result = null;
+ if (bankServiceImpl.getUser() != null)
+ {
+ // 用户名不为空,说明有权限
+ result = method.invoke(targetObject, args);
+ }
+ else
+ {
+ System.out.println("用户不能为空.");
+ }
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/DynamicProxyTest.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/DynamicProxyTest.java
new file mode 100644
index 00000000..748b30e7
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/DynamicProxyTest.java
@@ -0,0 +1,20 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.demo;
+
+import java.lang.reflect.Proxy;
+
+public class DynamicProxyTest
+{
+ public static void main(String[] args)
+ {
+ HelloImpl helloImpl = new HelloImpl();
+ LogHandler handler = new LogHandler(helloImpl);
+
+ // 这里把handler与impl新生成的代理类相关联
+ Hello hello = (Hello) Proxy.newProxyInstance(helloImpl.getClass().getClassLoader(), helloImpl.getClass()
+ .getInterfaces(), handler);
+
+ // 这里无论访问哪个方法,都是会把请求转发到handler.invoke
+ hello.sayHello("Denny");
+ hello.sayHi("Tom");
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/Hello.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/Hello.java
new file mode 100644
index 00000000..7d47d4de
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/Hello.java
@@ -0,0 +1,8 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.demo;
+
+public interface Hello
+{
+ public void sayHello(String name);
+
+ public void sayHi(String name);
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/HelloImpl.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/HelloImpl.java
new file mode 100644
index 00000000..7919bad9
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/HelloImpl.java
@@ -0,0 +1,14 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.demo;
+
+public class HelloImpl implements Hello
+{
+ public void sayHello(String name)
+ {
+ System.out.println("Hello, " + name);
+ }
+
+ public void sayHi(String name)
+ {
+ System.out.println("hi, " + name);
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/LogHandler.java b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/LogHandler.java
new file mode 100644
index 00000000..beb12fca
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/reflection/proxy/dynamicproxy/demo/LogHandler.java
@@ -0,0 +1,32 @@
+package com.xdc.basic.api.reflection.proxy.dynamicproxy.demo;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+public class LogHandler implements InvocationHandler
+{
+ private Object targetObject;
+
+ public LogHandler(Object obj)
+ {
+ this.targetObject = obj;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+ {
+ doBefore();
+ Object result = method.invoke(targetObject, args);
+ doAfter();
+ return result;
+ }
+
+ private void doBefore()
+ {
+ System.out.println("log: 要开始执行了!");
+ }
+
+ private void doAfter()
+ {
+ System.out.println("log: 已经执行完了!");
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/regex/ExpressionParse.java b/basicKnowledge/src/com/xdc/basic/api/regex/ExpressionParse.java
new file mode 100644
index 00000000..52c0cd83
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/regex/ExpressionParse.java
@@ -0,0 +1,52 @@
+package com.xdc.basic.api.regex;
+
+import java.util.ArrayList;
+import java.util.Scanner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 表达式解析: 整数1 加或乘 整数2 用正则表达式进行输入验证
+ *
+ * @author xdc
+ *
+ */
+public class ExpressionParse
+{
+ public static void main(String[] args)
+ {
+ @SuppressWarnings("resource")
+ Scanner cin = new Scanner(System.in);
+
+ // \s:代表空白,-?:代表0个或一个减号,\d:代表数字
+ String regex = "^\\s*(-?\\d+)\\s*([+*])\\s*(-?\\d+)\\s*$";
+ Pattern pattern = Pattern.compile(regex);
+
+ while (true)
+ {
+ String line = cin.nextLine();
+ line = line.trim();
+ if (line.isEmpty())
+ {
+ continue;
+ }
+
+ Matcher matcher = pattern.matcher(line);
+ if (matcher.find())
+ {
+ ArrayList items = new ArrayList();
+ // 下面的循环中,先加入整表达式,在依次放入:整数1, 加或乘, 整数2。
+ for (int i = 0; i <= matcher.groupCount(); i++)
+ {
+ String item = matcher.group(i);
+ items.add(item);
+ }
+ System.out.println(items);
+ }
+ else
+ {
+ System.out.println("表达式不合法!");
+ }
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/regex/RegexTest.java b/basicKnowledge/src/com/xdc/basic/api/regex/RegexTest.java
new file mode 100644
index 00000000..907e07c6
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/regex/RegexTest.java
@@ -0,0 +1,186 @@
+package com.xdc.basic.api.regex;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Test;
+
+public class RegexTest
+{
+ @Test
+ public void searchWord()
+ {
+ String word = "there";
+
+ String regex = "\\b" + word + "\\b";
+ String input = "Where there is a will there is a way.";
+
+ regexSearch(regex, input);
+ }
+
+ @Test
+ public void searchWordPrefix()
+ {
+ String wordPrefix = "the";
+
+ String regex = "\\b" + wordPrefix + "[a-zA-Z]+\\b";
+ String input = "Where there is a will there is a way.";
+
+ regexSearch(regex, input);
+ }
+
+ @Test
+ public void getAllWord()
+ {
+ String regex = "\\b[a-zA-Z]+\\b";
+ String input = "Where there is a will there is a way.";
+
+ regexSearch(regex, input);
+ }
+
+ @Test
+ public void ExpressionParse()
+ {
+ // 表达式解析: 整数1 加或乘 整数2
+ // \s:代表空白,-?:代表0个或一个减号,\d:代表数字
+ String regex = "^\\s*(-?\\d+)\\s*([+*])\\s*(-?\\d+)\\s*$";
+ String input = " 11 * 12 ";
+
+ regexSearch(regex, input);
+ }
+
+ @Test
+ public void searchWordCaseInsensitive1()
+ {
+ String word = "thERE";
+
+ String regex = "(?i)\\b" + word + "\\b";
+ String input = "Where there is a will there is a way.";
+
+ regexSearch(regex, input);
+ }
+
+ @Test
+ public void searchWordCaseInsensitive2()
+ {
+ String word = "thERE";
+
+ String regex = "\\b" + word + "\\b";
+ String input = "Where there is a will there is a way.";
+
+ int flags = Pattern.CASE_INSENSITIVE;
+ regexSearch(regex, input, flags);
+ }
+
+ @Test
+ public void patternFlags()
+ {
+ String word = "thERE";
+
+ String regex = "\\b" + word + "\\b";
+ String input = "Where there is a will there is a way.";
+
+ // 常用的标志
+ // 常量-----------------------等价的内嵌标志表达式--意义
+ // Pattern.CASE_INSENSITIVE (?i) 启用不区分大小写匹配。默认情况下,仅匹配 US-ASCII 字符集中的字符。
+ // Pattern.COMMENTS (?x) 模式中允许存在空白和注释。在这种模式下,空白和以#开始的直到行尾的内嵌注释会被忽略。
+ // Pattern.MULTILINE (?m) 启用多行(multiline)模式。在多行模式下,表达式^和$分别匹配输入序列行结束符前面和行结束符的前面。默认情况下,表达式仅匹配整个输入序列的开始和结尾。
+ // Pattern.DOTALL (?s) 启用 dotall 模式。在 dotall 模式下,表达式.匹配包括行结束符在内的任意字符。
+ // Pattern.UNICODE_CASE (?u) 配合CASE_INSENSITIVE标志来启用,使 Unicode字符不区分大小写匹配
+
+ int flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
+ regexSearch(regex, input, flags);
+ }
+
+ @Test
+ public void patternSplit()
+ {
+ String regex = "\\d";
+ String input = "one9two4three7four1five";
+
+ Pattern pattern = Pattern.compile(regex);
+ String[] items = pattern.split(input);
+ for (String item : items)
+ {
+ System.out.println(item);
+ }
+ }
+
+ /**
+ * 比matcher.replaceAll(replacement)灵活,可以在每个匹配出替换为不同的值。 用哪个是需求而定。
+ */
+ @Test
+ public void matcherReplacement()
+ {
+ String regex = "\\d";
+ String input = "one9two4three7four1five";
+
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(input); // 获得匹配器对象
+
+ StringBuffer sb = new StringBuffer();
+ while (matcher.find())
+ {
+ String replace = RandomStringUtils.random(1, "!@#$");
+ // 处理特殊字符\和$,在前面添加转义符\
+ replace = Matcher.quoteReplacement(replace);
+ System.out.println("Random char: " + replace);
+ matcher.appendReplacement(sb, replace);
+ }
+ matcher.appendTail(sb);
+ System.out.println(sb.toString());
+ }
+
+ private void regexSearch(String regex, String input)
+ {
+ regexSearch(regex, input, 0);
+ }
+
+ private void regexSearch(String regex, String input, int flags)
+ {
+ Pattern pattern = null;
+ Matcher matcher = null;
+ try
+ {
+ pattern = Pattern.compile(regex, flags);
+ matcher = pattern.matcher(input);
+ }
+ catch (PatternSyntaxException pse)
+ {
+ System.out.println("There is a problem with the regular expression!");
+ System.out.println("The pattern in question is: " + pse.getPattern());
+ System.out.println("The description is: " + pse.getDescription());
+ System.out.println("The message is: " + pse.getMessage());
+ System.out.println("The index is: " + pse.getIndex());
+ System.exit(0);
+ }
+
+ int count = 0;
+ // 一直不停的找,直到结尾
+ while (matcher.find())
+ {
+ System.out.println("======================================");
+ count++;
+ System.out.println("Match number : " + count);
+ System.out.println("Match text : " + matcher.group());
+ System.out.println("Match start index : " + matcher.start());
+ System.out.println("Match end index : " + matcher.end());
+
+ // matcher.groupCount()方法返回int类型值,表示当前 Matcher模式中捕获组的数量。
+ // 有一个特别的组——组 0,它表示整个表达式。这个组不包括在groupCount的报告范围内。因此注意下面需使用<=号。
+ // 因此matcher.group(0)与matcher.group()是等效的。
+ for (int i = 0; i <= matcher.groupCount(); i++)
+ {
+ System.out.println(" Group number : " + i);
+ System.out.println(" Group text : " + matcher.group(i));
+ System.out.println(" Group start index : " + matcher.start(i));
+ System.out.println(" Group end index : " + matcher.end(i));
+ System.out.println();
+ }
+
+ System.out.println();
+ }
+ }
+}
diff --git "a/basicKnowledge/src/com/xdc/basic/api/regex/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.txt" "b/basicKnowledge/src/com/xdc/basic/api/regex/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.txt"
new file mode 100644
index 00000000..afaf1ef0
--- /dev/null
+++ "b/basicKnowledge/src/com/xdc/basic/api/regex/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.txt"
@@ -0,0 +1,69 @@
+引自:http://www.jb51.net/tools/regex.htm
+
+正则表达式通常用于两种任务:1.验证,2.搜索/替换。用于验证时,通常需要在前后分别加上^和$,以匹配整个待验证字符串;搜索/替换时是否加上此限定则根据搜索的要求而定,此外,也有可能要在前后加上\b而不是^和$。
+
+
+==========================================================================================================
+引自:http://www.jb51.net/tools/zhengze.htm?1352600907
+
+各式各样的正则表达式参考大全:
+^\d+$ //匹配非负整数(正整数 + 0)
+//匹配整数 ^\d+(\.\d+)?$ //匹配非负浮点数(正浮点数 + 0)
+^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$ //匹配正浮点数
+^((-\d+(\.\d+)?)|(0+(\.0+)?))$ //匹配非正浮点数(负浮点数 + 0)
+^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$ //匹配负浮点数
+^(-?\d+)(\.\d+)?$ //匹配浮点数
+^[A-Za-z]+$ //匹配由26个英文字母组成的字符串
+^[A-Z]+$ //匹配由26个英文字母的大写组成的字符串
+^[a-z]+$ //匹配由26个英文字母的小写组成的字符串
+^[A-Za-z0-9]+$ //匹配由数字和26个英文字母组成的字符串
+^\w+$ //匹配由数字、26个英文字母或者下划线组成的字符串
+^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$ //匹配email地址
+^[a-zA-z]+://匹配(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$ //匹配url
+
+匹配中文字符的正则表达式: [\u4e00-\u9fa5]
+匹配双字节字符(包括汉字在内):[^\x00-\xff]
+匹配空行的正则表达式: \n[\s| ]*\r
+匹配HTML标记的正则表达式: /<(.*)>.*<\/>|<(.*) \/>/
+匹配首尾空格的正则表达式: (^\s*)|(\s*$)
+匹配Email地址的正则表达式: \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
+匹配网址URL的正则表达式: ^[a-zA-z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$
+匹配国内电话号码: (\d{3}-|\d{4}-)?(\d{8}|\d{7})?
+匹配腾讯QQ号: ^[1-9]*[1-9][0-9]*$
+匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
+
+下表是元字符及其在正则表达式上下文中的行为的一个完整列表,具体到每个正则表达式符号:
+\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个后向引用、或一个八进制转义符。
+^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的Multiline 属性,^ 也匹配 ’\n’ 或 ’\r’ 之后的位置。
+$ 匹配输入字符串的结束位置。如果设置了 RegExp 对象的Multiline 属性,$ 也匹配 ’\n’ 或 ’\r’ 之前的位置。
+* 匹配前面的子表达式零次或多次。
++ 匹配前面的子表达式一次或多次。+ 等价于 {1,}。
+? 匹配前面的子表达式零次或一次。? 等价于 {0,1}。
+{n} n 是一个非负整数,匹配确定的n 次。
+{n,} n 是一个非负整数,至少匹配n 次。
+{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。在逗号和两个数之间不能有空格。
+? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。
+. 匹配除 "\n" 之外的任何单个字符。要匹配包括 ’\n’ 在内的任何字符,请使用象 ’[.\n]’ 的模式。
+(pattern) 匹配pattern 并获取这一匹配。 (?:pattern) 匹配pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。 (?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。 (?!pattern) 负向预查,与(?=pattern)作用相反 x|y 匹配 x 或 y。
+[xyz] 字符集合。
+[^xyz] 负值字符集合。
+[a-z] 字符范围,匹配指定范围内的任意字符。
+[^a-z] 负值字符范围,匹配任何不在指定范围内的任意字符。
+\b 匹配一个单词边界,也就是指单词和空格间的位置。
+\B 匹配非单词边界。
+\cx 匹配由x指明的控制字符。
+\d 匹配一个数字字符。等价于 [0-9]。
+\D 匹配一个非数字字符。等价于 [^0-9]。
+\f 匹配一个换页符。等价于 \x0c 和 \cL。
+\n 匹配一个换行符。等价于 \x0a 和 \cJ。
+\r 匹配一个回车符。等价于 \x0d 和 \cM。
+\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
+\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
+\t 匹配一个制表符。等价于 \x09 和 \cI。
+\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
+\w 匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。
+\W 匹配任何非单词字符。等价于 ’[^A-Za-z0-9_]’。
+\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。
+\num 匹配 num,其中num是一个正整数。对所获取的匹配的引用。
+\n 标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
+\nm 标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。 \nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八.
diff --git a/basicKnowledge/src/com/xdc/basic/api/rmi/client/RMIClient.java b/basicKnowledge/src/com/xdc/basic/api/rmi/client/RMIClient.java
new file mode 100644
index 00000000..4e360bdb
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/rmi/client/RMIClient.java
@@ -0,0 +1,57 @@
+package com.xdc.basic.api.rmi.client;
+
+import java.net.MalformedURLException;
+import java.rmi.Naming;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.util.Scanner;
+
+import com.xdc.basic.api.rmi.intf.IHelloRMI;
+
+/**
+ * 客户端程序
+ *
+ * @author xdc
+ *
+ */
+public class RMIClient
+{
+
+ public static void main(String[] args)
+ {
+ Scanner cin = new Scanner(System.in);
+ try
+ {
+ String ip = new String();
+ int port;
+ System.out.print("请输入服务器ip:");
+ ip = cin.nextLine();
+ System.out.print("请输入服务器端口号:");
+ port = cin.nextInt();
+
+ com.xdc.basic.api.rmi.intf.IHelloRMI iRmi = (IHelloRMI) Naming.lookup("rmi://" + ip + ":" + port
+ + "/My_RMI");
+
+ System.out.println(iRmi.sayHello());
+
+ }
+ catch (MalformedURLException e)
+ {
+ e.printStackTrace();
+ }
+ catch (RemoteException e)
+ {
+ e.printStackTrace();
+ }
+ catch (NotBoundException e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ cin.close();
+ }
+
+ }
+
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/rmi/intf/IHelloRMI.java b/basicKnowledge/src/com/xdc/basic/api/rmi/intf/IHelloRMI.java
new file mode 100644
index 00000000..170addd2
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/rmi/intf/IHelloRMI.java
@@ -0,0 +1,15 @@
+package com.xdc.basic.api.rmi.intf;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * 远程接口
+ *
+ * @author xdc
+ *
+ */
+public interface IHelloRMI extends Remote
+{
+ public String sayHello() throws RemoteException;
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/rmi/server/HelloRMIImpl.java b/basicKnowledge/src/com/xdc/basic/api/rmi/server/HelloRMIImpl.java
new file mode 100644
index 00000000..4f6cb69c
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/rmi/server/HelloRMIImpl.java
@@ -0,0 +1,30 @@
+package com.xdc.basic.api.rmi.server;
+
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+import com.xdc.basic.api.rmi.intf.IHelloRMI;
+
+/**
+ * 接口的实现
+ *
+ * @author xdc
+ *
+ */
+public class HelloRMIImpl extends UnicastRemoteObject implements IHelloRMI
+{
+
+ private static final long serialVersionUID = 1455115818555556704L;
+
+ public HelloRMIImpl() throws RemoteException
+ {
+ super();
+ }
+
+ @Override
+ public String sayHello() throws RemoteException
+ {
+ return "Hello RMI";
+ }
+
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/rmi/server/RMIServer.java b/basicKnowledge/src/com/xdc/basic/api/rmi/server/RMIServer.java
new file mode 100644
index 00000000..73f91136
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/rmi/server/RMIServer.java
@@ -0,0 +1,44 @@
+package com.xdc.basic.api.rmi.server;
+
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Scanner;
+
+/**
+ * 服务器端
+ *
+ * RMI,远程方法调用(Remote Method Invocation)是Enterprise JavaBeans的支柱,
+ * 是建立分布式Java应用程序的方便途径。RMI是非常容易使用的,但是它非常的强大。
+ *
+ * RMI的基础是接口,RMI构架基于一个重要的原理:定义接口和定义接口的具体实现是分开的。
+ *
+ * @author xdc
+ *
+ */
+public class RMIServer
+{
+ public static void main(String[] args)
+ {
+ Scanner cin = new Scanner(System.in);
+ try
+ {
+ int port;
+ System.out.print("请输入监听端口号:");
+ port = cin.nextInt();
+ HelloRMIImpl rmi = new HelloRMIImpl();
+ Registry r = LocateRegistry.createRegistry(port);
+ r.rebind("My_RMI", rmi);
+ System.out.println("服务运行中...");
+ System.out.println("服务端口号为:" + port);
+ }
+ catch (RemoteException e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ cin.close();
+ }
+ }
+}
diff --git "a/basicKnowledge/src/com/xdc/basic/api/rmi/\346\211\223\345\214\205\345\217\212\346\265\213\350\257\225\346\226\271\346\263\225.txt" "b/basicKnowledge/src/com/xdc/basic/api/rmi/\346\211\223\345\214\205\345\217\212\346\265\213\350\257\225\346\226\271\346\263\225.txt"
new file mode 100644
index 00000000..c0973305
--- /dev/null
+++ "b/basicKnowledge/src/com/xdc/basic/api/rmi/\346\211\223\345\214\205\345\217\212\346\265\213\350\257\225\346\226\271\346\263\225.txt"
@@ -0,0 +1,8 @@
+(1)用eclipse分别将两工程打包:
+方法一:导出--java--jar文件,写好文件名和选好Main类,其他默认。(推荐)
+方法二:导出--java--jar文件,写好文件名和选好启动配置,其他默认。
+方法三:手工执行jar打包,略。
+
+(2)在两个命令行窗口分别执行:
+ java -jar rmiServer
+ jave -jar rmiClient
diff --git a/basicKnowledge/src/com/xdc/basic/api/serialization/SerializationTest.java b/basicKnowledge/src/com/xdc/basic/api/serialization/SerializationTest.java
new file mode 100644
index 00000000..0fe493b1
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/serialization/SerializationTest.java
@@ -0,0 +1,55 @@
+package com.xdc.basic.api.serialization;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import com.xdc.basic.skills.GetCurPath;
+
+public class SerializationTest
+{
+ public static void main(String[] args)
+ {
+ String curPath = GetCurPath.getCurPath();
+
+ // Object serialization
+ try
+ {
+ Student student1 = new Student("xdc", 25);
+ System.out.println("student1: " + student1);
+
+ FileOutputStream fos = new FileOutputStream(curPath + "serial");
+ ObjectOutputStream oos = new ObjectOutputStream(fos);
+
+ oos.writeObject(student1);
+
+ oos.flush();
+ oos.close();
+ }
+ catch (Exception e)
+ {
+ System.out.println("Exception during serialization:" + e);
+ System.exit(0);
+ }
+
+ // Object deserialization
+ try
+ {
+ Student student2;
+ FileInputStream fis = new FileInputStream(curPath + "serial");
+ ObjectInputStream ois = new ObjectInputStream(fis);
+
+ student2 = (Student) ois.readObject();
+
+ ois.close();
+ System.out.println("student2: " + student2);
+ }
+ catch (Exception e)
+ {
+ System.out.println("Exception during deserialization:" + e);
+ System.exit(0);
+ }
+ }
+
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/serialization/Student.java b/basicKnowledge/src/com/xdc/basic/api/serialization/Student.java
new file mode 100644
index 00000000..a6b7f550
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/serialization/Student.java
@@ -0,0 +1,48 @@
+package com.xdc.basic.api.serialization;
+
+import java.io.Serializable;
+
+public class Student implements Serializable
+{
+ // 序列化标志
+ // Add generated serial version ID
+ // 添加已生成的串行版本标识
+
+ private static final long serialVersionUID = -5104809987465264163L;
+
+ private String name;
+ private int age;
+
+ public Student(String name, int age)
+ {
+ super();
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public int getAge()
+ {
+ return age;
+ }
+
+ public void setAge(int age)
+ {
+ this.age = age;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Student [name=" + name + ", age=" + age + "]";
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/serialization/serial b/basicKnowledge/src/com/xdc/basic/api/serialization/serial
new file mode 100644
index 00000000..51a53e76
Binary files /dev/null and b/basicKnowledge/src/com/xdc/basic/api/serialization/serial differ
diff --git "a/basicKnowledge/src/com/xdc/basic/api/socket/Socket\347\274\226\347\250\213\347\256\200\350\256\260.docx" "b/basicKnowledge/src/com/xdc/basic/api/socket/Socket\347\274\226\347\250\213\347\256\200\350\256\260.docx"
new file mode 100644
index 00000000..dfb49151
Binary files /dev/null and "b/basicKnowledge/src/com/xdc/basic/api/socket/Socket\347\274\226\347\250\213\347\256\200\350\256\260.docx" differ
diff --git a/basicKnowledge/src/com/xdc/basic/api/socket/tcp/MyClient.java b/basicKnowledge/src/com/xdc/basic/api/socket/tcp/MyClient.java
new file mode 100644
index 00000000..37ecaa95
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/socket/tcp/MyClient.java
@@ -0,0 +1,34 @@
+package com.xdc.basic.api.socket.tcp;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.net.Socket;
+
+public class MyClient
+{
+ public static void main(String[] args)
+ {
+ try
+ {
+ // 创建连接到服务器的Socket对象
+ Socket sc = new Socket("127.0.0.1", 9876);
+ // 获取当前连接的输入流,并使用处理流进行封装
+ DataInputStream din = new DataInputStream(sc.getInputStream());
+ // 获取当前连接的输出流,并使用处理流进行封装
+ DataOutputStream dout = new DataOutputStream(sc.getOutputStream());
+ // 向服务器发送消息
+ dout.writeUTF("请问你那现在几点?");
+ // 读取服务器的返回消息并打印
+ System.out.println(din.readUTF());
+ // 关闭流
+ din.close();
+ dout.close();
+ // 关闭此Socket连接
+ sc.close();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/socket/tcp/MyServer.java b/basicKnowledge/src/com/xdc/basic/api/socket/tcp/MyServer.java
new file mode 100644
index 00000000..ea5cb51b
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/socket/tcp/MyServer.java
@@ -0,0 +1,61 @@
+package com.xdc.basic.api.socket.tcp;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Date;
+
+public class MyServer
+{
+ public static void main(String[] args)
+ {
+ int count = 0;// 声明用来计数的int局部变量
+ ServerSocket server = null;
+ try
+ {
+ // 创建绑定到9876端口的ServerSocket对象
+ server = new ServerSocket(9876);
+ System.out.println("服务器对9876端口正在进行监听...");
+ // 服务器循环接收客户端的请求,为不同的客户端提供服务
+ while (true)
+ {
+ // 接收客户端的连接请求,若有连接请求返回连接对应的Socket对象
+ Socket sc = server.accept();
+ // 获取当前连接的输入流,并使用处理流进行封装
+ DataInputStream din = new DataInputStream(sc.getInputStream());
+ // 获取当前连接的输出流,并使用处理流进行封装
+ DataOutputStream dout = new DataOutputStream(sc.getOutputStream());
+ // 打印客户端的信息
+ System.out.println("这是第" + (++count) + "个客户访问");
+ System.out.println("客户端IP地址:" + sc.getInetAddress().getHostAddress());
+ System.out.println("本地端口号:" + sc.getLocalPort());
+ System.out.println("客户端信息:" + din.readUTF());
+ // 向客户端发送回应信息
+ dout.writeUTF("服务器的时间为:" + (new Date()));
+ // 关闭流
+ din.close();
+ dout.close();
+ // 关闭此Socket连接
+ sc.close();
+ }
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ try
+ {
+ server.close();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/socket/udp/FortuneClient.java b/basicKnowledge/src/com/xdc/basic/api/socket/udp/FortuneClient.java
new file mode 100644
index 00000000..01f90f3d
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/socket/udp/FortuneClient.java
@@ -0,0 +1,53 @@
+package com.xdc.basic.api.socket.udp;
+
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+class FortuneClient
+{
+ public String getMessage()
+ {
+ String fortune;
+ try
+ {
+ // 创建数据报套接字
+ DatagramSocket socket = new DatagramSocket();
+
+ // 创建缓冲区
+ byte[] data = new byte[256];
+ // 创建发送数据包
+ DatagramPacket sendPacket = new DatagramPacket(data, data.length, InetAddress.getByName("127.0.0.1"), 1114);
+ // 发送报文
+ socket.send(sendPacket);
+
+ // 创建接收数据包
+ DatagramPacket resivePacket = new DatagramPacket(data, data.length);
+ // 等待接收报文
+ socket.receive(resivePacket);
+
+ // 将数据内容由字节转换成字符
+ fortune = new String(resivePacket.getData());
+ // 关闭套接字
+ socket.close();
+ }
+ catch (UnknownHostException e)
+ {
+ System.err.println("Exception: host could not be found!");
+ return null;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ return fortune;
+ }
+
+ public static void main(String args[])
+ {
+ FortuneClient client = new FortuneClient();
+ System.out.println(client.getMessage());
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/socket/udp/FortuneServer.java b/basicKnowledge/src/com/xdc/basic/api/socket/udp/FortuneServer.java
new file mode 100644
index 00000000..b88c9072
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/socket/udp/FortuneServer.java
@@ -0,0 +1,81 @@
+package com.xdc.basic.api.socket.udp;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.SocketException;
+
+import org.apache.commons.io.IOUtils;
+
+import com.xdc.basic.skills.GetCurPath;
+
+class FortuneServer extends Thread
+{
+ DatagramSocket ServerSocket;
+
+ public FortuneServer()
+ {
+ super("FortuneServer");
+ try
+ {
+ ServerSocket = new DatagramSocket(1114);
+ System.out.println("FortuneServer up and running...");
+ }
+ catch (SocketException e)
+ {
+ System.err.println("Exception: couldn't create datagram sockter");
+ System.exit(1);
+ }
+ }
+
+ public static void main(String args[])
+ {
+ FortuneServer server = new FortuneServer();
+ server.start();
+ }
+
+ public void run()
+ {
+ String curPath = GetCurPath.getCurPath();
+
+ FileInputStream inStream = null;
+ while (true)
+ {
+ try
+ {
+ // 创建缓冲区
+ byte[] data = new byte[256];
+ // 创建接收数据包
+ DatagramPacket rPacket = new DatagramPacket(data, data.length);
+
+ System.out.println("等待客户端连接...");
+ // 等待接收数据包
+ ServerSocket.receive(rPacket);
+ System.out.println("已有客户端发来请求: " + rPacket.getAddress().getHostAddress() + ":" + rPacket.getPort());
+
+ // 读取待发送的内容
+ inStream = new FileInputStream(new File(curPath + "Fortunes.txt"));
+ if (inStream.read(data) <= 0)
+ {
+ System.err.println("Error: couldn't read fortunes");
+ }
+
+ // 创建发送数据包
+ DatagramPacket sPacket = new DatagramPacket(data, data.length, rPacket.getAddress(), rPacket.getPort());
+ // 发送报文
+ ServerSocket.send(sPacket);
+ }
+ catch (Exception e)
+ {
+ System.err.println("Exception: " + e);
+ e.printStackTrace();
+ }
+ finally
+ {
+ // 大师鸟悄的关闭输入流
+ IOUtils.closeQuietly(inStream);
+ }
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/socket/udp/Fortunes.txt b/basicKnowledge/src/com/xdc/basic/api/socket/udp/Fortunes.txt
new file mode 100644
index 00000000..e3df38d1
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/socket/udp/Fortunes.txt
@@ -0,0 +1,4 @@
+This is a test.
+Here is all what I want to send your message:
+Facts speak plainer than words.
+I love this game very much.
\ No newline at end of file
diff --git "a/basicKnowledge/src/com/xdc/basic/api/socket/\346\225\260\346\215\256\346\212\245\351\200\232\344\277\241\345\222\214\346\265\201\345\274\217\351\200\232\344\277\241\347\232\204\345\214\272\345\210\253.docx" "b/basicKnowledge/src/com/xdc/basic/api/socket/\346\225\260\346\215\256\346\212\245\351\200\232\344\277\241\345\222\214\346\265\201\345\274\217\351\200\232\344\277\241\347\232\204\345\214\272\345\210\253.docx"
new file mode 100644
index 00000000..2e5aaf22
Binary files /dev/null and "b/basicKnowledge/src/com/xdc/basic/api/socket/\346\225\260\346\215\256\346\212\245\351\200\232\344\277\241\345\222\214\346\265\201\345\274\217\351\200\232\344\277\241\347\232\204\345\214\272\345\210\253.docx" differ
diff --git "a/basicKnowledge/src/com/xdc/basic/api/socket/\346\265\201\345\274\217\345\245\227\346\216\245\345\255\227\357\274\210TCP\357\274\211\345\222\214 \346\225\260\346\215\256\346\212\245\345\245\227\346\216\245\345\255\227\357\274\210UDP\357\274\211\347\232\204\345\214\272\345\210\253.docx" "b/basicKnowledge/src/com/xdc/basic/api/socket/\346\265\201\345\274\217\345\245\227\346\216\245\345\255\227\357\274\210TCP\357\274\211\345\222\214 \346\225\260\346\215\256\346\212\245\345\245\227\346\216\245\345\255\227\357\274\210UDP\357\274\211\347\232\204\345\214\272\345\210\253.docx"
new file mode 100644
index 00000000..bdd67728
Binary files /dev/null and "b/basicKnowledge/src/com/xdc/basic/api/socket/\346\265\201\345\274\217\345\245\227\346\216\245\345\255\227\357\274\210TCP\357\274\211\345\222\214 \346\225\260\346\215\256\346\212\245\345\245\227\346\216\245\345\255\227\357\274\210UDP\357\274\211\347\232\204\345\214\272\345\210\253.docx" differ
diff --git a/basicKnowledge/src/com/xdc/basic/api/sort/CompareTest.java b/basicKnowledge/src/com/xdc/basic/api/sort/CompareTest.java
new file mode 100644
index 00000000..af71abc2
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/sort/CompareTest.java
@@ -0,0 +1,77 @@
+package com.xdc.basic.api.sort;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class CompareTest
+{
+ /**
+ * 本例所有排序:分数降序,年龄降序
+ *
+ * @param args
+ */
+ public static void main(String[] args)
+ {
+ // 列表
+ List students = new ArrayList();
+ students.add(new Student("xudachao", 100, 25));
+ students.add(new Student("wangzhiwei", 88, 24));
+ students.add(new Student("gengxue", 98, 24));
+
+ listSort(students);
+
+ // 数组
+ Student[] studentArr = students.toArray(new Student[students.size()]);
+
+ arraySort(studentArr);
+ }
+
+ private static void arraySort(Student[] studentArr)
+ {
+ // 方式一
+ Arrays.sort(studentArr, new Comparator()
+ {
+ @Override
+ public int compare(Student o1, Student o2)
+ {
+ int scoreDiff = o1.getScore() - o2.getScore();
+ if (scoreDiff != 0)
+ return scoreDiff;
+
+ int ageDiff = o1.getAge() - o2.getAge();
+ return ageDiff;
+ }
+ });
+
+ // 方式二
+ Arrays.sort(studentArr);
+
+ System.out.println(Arrays.toString(studentArr));
+ }
+
+ private static void listSort(List students)
+ {
+ // 方式一
+ Collections.sort(students, new Comparator()
+ {
+ @Override
+ public int compare(Student o1, Student o2)
+ {
+ int scoreDiff = o1.getScore() - o2.getScore();
+ if (scoreDiff != 0)
+ return scoreDiff;
+
+ int ageDiff = o1.getAge() - o2.getAge();
+ return ageDiff;
+ }
+ });
+
+ // 方式二
+ Collections.sort(students);
+
+ System.out.println(students);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/sort/Student.java b/basicKnowledge/src/com/xdc/basic/api/sort/Student.java
new file mode 100644
index 00000000..0769de6d
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/sort/Student.java
@@ -0,0 +1,75 @@
+package com.xdc.basic.api.sort;
+
+import org.apache.commons.lang3.builder.CompareToBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+public class Student implements Comparable
+{
+ private String name;
+ private int score;
+ private int age;
+
+ public Student(String name, int score, int age)
+ {
+ super();
+ this.setName(name);
+ this.setScore(score);
+ this.setAge(age);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public int getScore()
+ {
+ return score;
+ }
+
+ public void setScore(int score)
+ {
+ this.score = score;
+ }
+
+ public int getAge()
+ {
+ return age;
+ }
+
+ public void setAge(int age)
+ {
+ this.age = age;
+ }
+
+ @Override
+ public String toString()
+ {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
+ }
+
+ // Two Objects that compare equal using equals(Object) should normally also
+ // compare equal using compareTo(Object).
+ // 先比较年龄,再比较姓名,再比较是否抽烟
+ @Override
+ public int compareTo(Student o)
+ {
+ // 用不用判断null呢?
+ Student that = o;
+ return new CompareToBuilder().append(this.score, that.score).append(this.age, that.age).toComparison();
+ }
+
+ // Two Objects that compare equal using equals(Object) should normally also
+ // compare equal using compareTo(Object).
+ // 不推荐。由于该类涉及到比较字段的顺序,所以并不推荐使用该族中的方法自动映射字段,而最好自己决定那些字段参与比较及它们的顺序。该族方法的返回值为一整数,意义同Comparable接口的compareTo方法。
+ public int compareTo2(Student o)
+ {
+ return CompareToBuilder.reflectionCompare(this, o);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/DeadLockTest.java b/basicKnowledge/src/com/xdc/basic/api/thread/DeadLockTest.java
new file mode 100644
index 00000000..e91f98ad
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/DeadLockTest.java
@@ -0,0 +1,83 @@
+package com.xdc.basic.api.thread;
+
+/**
+ * 死锁样例演示
+ *
+ * @author xdc
+ *
+ */
+public class DeadLockTest
+{
+ public static void main(String[] args)
+ {
+ DeadlockRisk dead = new DeadlockRisk();
+ MyThread t1 = new MyThread(dead, 1, 2);
+ MyThread t2 = new MyThread(dead, 3, 4);
+ MyThread t3 = new MyThread(dead, 5, 6);
+ MyThread t4 = new MyThread(dead, 7, 8);
+
+ t1.start();
+ t2.start();
+ t3.start();
+ t4.start();
+ }
+}
+
+class MyThread extends Thread
+{
+ private DeadlockRisk dead;
+ private int a;
+ private int b;
+
+ MyThread(DeadlockRisk dead, int a, int b)
+ {
+ this.dead = dead;
+ this.a = a;
+ this.b = b;
+ }
+
+ @Override
+ public void run()
+ {
+ dead.read();
+ dead.write(a, b);
+ }
+}
+
+class DeadlockRisk
+{
+ private static class Resource
+ {
+ public int value;
+ }
+
+ private Resource resourceA = new Resource();
+ private Resource resourceB = new Resource();
+
+ public int read()
+ {
+ synchronized (resourceA)
+ {
+ System.out.println("read():" + Thread.currentThread().getName() + "获取了resourceA的锁!");
+ synchronized (resourceB)
+ {
+ System.out.println("read():" + Thread.currentThread().getName() + "获取了resourceB的锁!");
+ return resourceB.value + resourceA.value;
+ }
+ }
+ }
+
+ public void write(int a, int b)
+ {
+ synchronized (resourceB)
+ {
+ System.out.println("write():" + Thread.currentThread().getName() + "获取了resourceB的锁!");
+ synchronized (resourceA)
+ {
+ System.out.println("write():" + Thread.currentThread().getName() + "获取了resourceA的锁!");
+ resourceA.value = a;
+ resourceB.value = b;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/InterruptTest.java b/basicKnowledge/src/com/xdc/basic/api/thread/InterruptTest.java
new file mode 100644
index 00000000..d529bdf1
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/InterruptTest.java
@@ -0,0 +1,40 @@
+package com.xdc.basic.api.thread;
+
+public class InterruptTest
+{
+
+ public static void main(String[] args)
+ {
+ Thread t = new Thread()
+ {
+ public void run()
+ {
+ System.out.println("执行run方法");
+ try
+ {
+ Thread.sleep(10000);
+ System.out.println("线程完成休眠");
+ }
+ catch (InterruptedException e)
+ {
+ System.out.println("休眠被打断");
+ return; // 返回到程序的调用处
+ }
+ System.out.println("线程正常终止");
+ }
+ };
+
+ t.start();
+
+ try
+ {
+ Thread.sleep(2000L);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+
+ t.interrupt(); // 2s后中断线程
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/JoinTest.java b/basicKnowledge/src/com/xdc/basic/api/thread/JoinTest.java
new file mode 100644
index 00000000..0263b560
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/JoinTest.java
@@ -0,0 +1,40 @@
+package com.xdc.basic.api.thread;
+
+import java.io.IOException;
+
+public class JoinTest
+{
+ public static void main(String[] args)
+ {
+ // 启动一线程,等待控制台输入,使用join()方法来暂停当前线程,直到其他线程调用
+ Thread t = new Thread()
+ {
+ public void run()
+ {
+ System.out.println("Reading");
+ try
+ {
+ System.in.read();
+ }
+ catch (IOException e)
+ {
+ System.err.println(e);
+ }
+ System.out.println("Thread finished.");
+ }
+ };
+ System.out.println("Starting");
+ t.start();
+
+ try
+ {
+ System.out.println("Joining");
+ t.join();
+ }
+ catch (InterruptedException e)
+ {
+ System.out.println("Who dares imterrupt my sleep?");
+ }
+ System.out.println("Main finished.");
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/java4android/thread/extendsthead/Test.java b/basicKnowledge/src/com/xdc/basic/api/thread/basic/extendsthead/Test.java
similarity index 77%
rename from basicKnowledge/src/com/xdc/basic/java4android/thread/extendsthead/Test.java
rename to basicKnowledge/src/com/xdc/basic/api/thread/basic/extendsthead/Test.java
index 763375cc..fab9e2ef 100644
--- a/basicKnowledge/src/com/xdc/basic/java4android/thread/extendsthead/Test.java
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/basic/extendsthead/Test.java
@@ -1,16 +1,16 @@
-package com.xdc.basic.java4android.thread.extendsthead;
-
-class Test
-{
- public static void main(String[] args)
- {
- // 生成线程类的对象
- MyThread t = new MyThread();
- // 启动线程 不能用t.run(); 这样的话,不会启动新的线程还是在当前线程中执行,因为咱们重写的run()函数和其他的成员函数没有区别
- t.start();
- for (int i = 0; i < 100; i++)
- {
- System.out.println("main-->" + i);
- }
- }
-}
+package com.xdc.basic.api.thread.basic.extendsthead;
+
+class Test
+{
+ public static void main(String[] args)
+ {
+ // 生成线程类的对象
+ ThreadExt t = new ThreadExt();
+ // 启动线程 不能用t.run(); 这样的话,不会启动新的线程还是在当前线程中执行,因为咱们重写的run()函数和其他的成员函数没有区别
+ t.start();
+ for (int i = 0; i < 100; i++)
+ {
+ System.out.println("main-->" + i);
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/java4android/thread/extendsthead/MyThread.java b/basicKnowledge/src/com/xdc/basic/api/thread/basic/extendsthead/ThreadExt.java
similarity index 52%
rename from basicKnowledge/src/com/xdc/basic/java4android/thread/extendsthead/MyThread.java
rename to basicKnowledge/src/com/xdc/basic/api/thread/basic/extendsthead/ThreadExt.java
index 6f3898f6..1e7d21e3 100644
--- a/basicKnowledge/src/com/xdc/basic/java4android/thread/extendsthead/MyThread.java
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/basic/extendsthead/ThreadExt.java
@@ -1,9 +1,9 @@
-package com.xdc.basic.java4android.thread.extendsthead;
-
-class MyThread extends Thread{
- public void run(){
- for(int i = 0; i < 100;i++){
- System.out.println("MyThread-->" + i);
- }
- }
-}
+package com.xdc.basic.api.thread.basic.extendsthead;
+
+class ThreadExt extends Thread{
+ public void run(){
+ for(int i = 0; i < 100;i++){
+ System.out.println("MyThread-->" + i);
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/basic/implcallable/CallableImpl.java b/basicKnowledge/src/com/xdc/basic/api/thread/basic/implcallable/CallableImpl.java
new file mode 100644
index 00000000..9ab5d7ec
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/basic/implcallable/CallableImpl.java
@@ -0,0 +1,12 @@
+package com.xdc.basic.api.thread.basic.implcallable;
+
+import java.util.concurrent.Callable;
+
+public class CallableImpl implements Callable
+{
+ @Override
+ public String call() throws Exception
+ {
+ return "I'm in callable.";
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/basic/implcallable/Test.java b/basicKnowledge/src/com/xdc/basic/api/thread/basic/implcallable/Test.java
new file mode 100644
index 00000000..013ccd25
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/basic/implcallable/Test.java
@@ -0,0 +1,17 @@
+package com.xdc.basic.api.thread.basic.implcallable;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+class Test
+{
+ public static void main(String[] args) throws InterruptedException, ExecutionException
+ {
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future future = executor.submit(new CallableImpl());
+ String result = future.get();
+ System.out.println(result);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/basic/implrunable/RunnableImpl.java b/basicKnowledge/src/com/xdc/basic/api/thread/basic/implrunable/RunnableImpl.java
new file mode 100644
index 00000000..5bab0cff
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/basic/implrunable/RunnableImpl.java
@@ -0,0 +1,39 @@
+package com.xdc.basic.api.thread.basic.implrunable;
+
+class RunnableImpl implements Runnable
+{
+ int i = 100;
+
+ public void run()
+ {
+ while (true)
+ {
+ System.out.println(Thread.currentThread().getName() + "-->" + i);
+ i--;
+ Thread.yield();
+ if (i < 0)
+ {
+ break;
+ }
+ }
+
+ }
+
+ // 这个应该是规范的写法,如果不这么写,出错很难发现
+ // public void run()
+ // {
+ // try
+ // {
+ // // dosomething
+ // }
+ // catch (Throwable e)
+ // {
+ // // log and throw
+ // throw e;
+ // }
+ // finally
+ // {
+ // // do some cleaning, close io and so on
+ // }
+ // }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/java4android/thread/synclock/Test.java b/basicKnowledge/src/com/xdc/basic/api/thread/basic/implrunable/Test.java
similarity index 84%
rename from basicKnowledge/src/com/xdc/basic/java4android/thread/synclock/Test.java
rename to basicKnowledge/src/com/xdc/basic/api/thread/basic/implrunable/Test.java
index f1214c67..cfa15c06 100644
--- a/basicKnowledge/src/com/xdc/basic/java4android/thread/synclock/Test.java
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/basic/implrunable/Test.java
@@ -1,20 +1,20 @@
-package com.xdc.basic.java4android.thread.synclock;
-
-class Test
-{
- public static void main(String[] args)
- {
- // 生成一个Runnable接口的实现类的对象
- RunnableImpl r = new RunnableImpl();
- // 生成一个Thread对象,并将Runnalbe接口的实
- // 现类的对象作为参数传递给该Thread对象
-
- Thread t = new Thread(r);
- t.setName("t1");
- t.start();
-
- Thread t2 = new Thread(r);
- t2.setName("t2");
- t2.start();
- }
-}
+package com.xdc.basic.api.thread.basic.implrunable;
+
+class Test
+{
+ public static void main(String[] args)
+ {
+ // 生成一个Runnable接口的实现类的对象
+ RunnableImpl r = new RunnableImpl();
+ // 生成一个Thread对象,并将Runnalbe接口的实
+ // 现类的对象作为参数传递给该Thread对象
+
+ Thread t = new Thread(r);
+ t.setName("t1");
+ t.start();
+
+ Thread t2 = new Thread(r);
+ t2.setName("t2");
+ t2.start();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/executor/ScheduledThreadPoolExecutorTest.java b/basicKnowledge/src/com/xdc/basic/api/thread/executor/ScheduledThreadPoolExecutorTest.java
new file mode 100644
index 00000000..784b2fcf
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/executor/ScheduledThreadPoolExecutorTest.java
@@ -0,0 +1,139 @@
+package com.xdc.basic.api.thread.executor;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * http://ketqi.blog.51cto.com/1130608/687681
+ *
+ * @author xdc
+ *
+ */
+public class ScheduledThreadPoolExecutorTest
+{
+ private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ public static void main(String[] args)
+ {
+ // 参数corePoolSize代表线程最小个数,即使它们空闲,线程数最大值无限制,动态增加
+ ScheduledExecutorService exec = Executors.newScheduledThreadPool(2);
+
+ long initialDelay = 0;
+ long period = 5000;
+ scheduleAtFixedRate(exec, initialDelay, period);
+ scheduleWithFixedDelay(exec, initialDelay, period);
+
+ long delay = 10000;
+ schedule(exec, delay);
+
+ cancelSchedule(exec, initialDelay, period);
+
+ try
+ {
+ Thread.sleep(50000);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+
+ exec.shutdown();
+ System.out.println("定时器关闭!");
+ }
+
+ private static void cancelSchedule(ScheduledExecutorService exec, long initialDelay, long period)
+ {
+ ScheduledFuture> scheduledFuture = exec.scheduleAtFixedRate(new Runnable()
+ {
+ public void run()
+ {
+ System.out.println("cancelSchedule: " + format.format(new Date()));
+ }
+ }, initialDelay, period, TimeUnit.MILLISECONDS);
+
+ try
+ {
+ Thread.sleep(20000);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+
+ scheduledFuture.cancel(false);
+ System.out.println("cancelSchedule: the schedule has been canceled!" + format.format(new Date()));
+ }
+
+ /**
+ * @param exec
+ * @param initialDelay
+ * @param period
+ */
+ private static void scheduleAtFixedRate(ScheduledExecutorService exec, long initialDelay, long period)
+ {
+ /**
+ * 每隔一段时间打印系统时间,互不影响的
+ * 创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;
+ * 也就是将在 initialDelay 后开始执行,然后在initialDelay+period 后执行,
+ * 接着在 initialDelay + 2 * period 后执行,依此类推。
+ */
+ exec.scheduleAtFixedRate(new Runnable()
+ {
+ public void run()
+ {
+ System.out.println("scheduleAtFixedRate: " + format.format(new Date()));
+ }
+ }, initialDelay, period, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * @param exec
+ * @param initialDelay
+ * @param period
+ */
+ private static void scheduleWithFixedDelay(ScheduledExecutorService exec, long initialDelay, long period)
+ {
+ /**
+ * 创建并执行一个在给定初始延迟后首次启用的定期操作,
+ * 随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。
+ */
+ exec.scheduleWithFixedDelay(new Runnable()
+ {
+ public void run()
+ {
+ System.out.println("scheduleWithFixedDelay-begin: " + format.format(new Date()));
+ try
+ {
+ Thread.sleep(2000);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ System.out.println("scheduleWithFixedDelay-end: " + format.format(new Date()));
+ }
+ }, initialDelay, period, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * @param exec
+ * @param delay
+ */
+ private static void schedule(ScheduledExecutorService exec, long delay)
+ {
+ /**
+ * 创建并执行在给定延迟后启用的一次性操作。
+ */
+ exec.schedule(new Runnable()
+ {
+ public void run()
+ {
+ System.out.println("The thread can only run once!");
+ }
+ }, delay, TimeUnit.MILLISECONDS);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/executor/ThreadFactoryTest.java b/basicKnowledge/src/com/xdc/basic/api/thread/executor/ThreadFactoryTest.java
new file mode 100644
index 00000000..a1964573
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/executor/ThreadFactoryTest.java
@@ -0,0 +1,67 @@
+package com.xdc.basic.api.thread.executor;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ *
+ * @author xdc
+ *
+ */
+public class ThreadFactoryTest
+{
+ public static void main(String[] args)
+ {
+ ThreadFactory threadFactory = new ThreadFactory()
+ {
+ private AtomicLong seq = new AtomicLong(0);
+
+ @Override
+ public Thread newThread(Runnable r)
+ {
+ Thread t = new Thread(r);
+ t.setName("MyThread-" + seq.getAndIncrement());
+ return t;
+ }
+ };
+
+ // 创建一个可重用固定线程数的线程池
+ ExecutorService pool = Executors.newFixedThreadPool(3, threadFactory);
+
+ // 创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
+ Thread t1 = new MyThread2();
+ Thread t2 = new MyThread2();
+ Thread t3 = new MyThread2();
+ Thread t4 = new MyThread2();
+ Thread t5 = new MyThread2();
+
+ // 将线程放入池中进行执行
+ pool.execute(t1);
+ pool.execute(t2);
+ pool.execute(t3);
+ pool.execute(t4);
+ pool.execute(t5);
+
+ // 关闭线程池
+ pool.shutdown();
+ }
+}
+
+class MyThread2 extends Thread
+{
+ @Override
+ public void run()
+ {
+ try
+ {
+ System.out.println(Thread.currentThread().getName() + "正在执行。。。");
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/executor/ThreadPoolExecutorTest.java b/basicKnowledge/src/com/xdc/basic/api/thread/executor/ThreadPoolExecutorTest.java
new file mode 100644
index 00000000..cd10d83f
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/executor/ThreadPoolExecutorTest.java
@@ -0,0 +1,53 @@
+package com.xdc.basic.api.thread.executor;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * http://www.cnblogs.com/jersey/archive/2011/03/30/2000231.html
+ *
+ * @author xdc
+ *
+ */
+public class ThreadPoolExecutorTest
+{
+ public static void main(String[] args)
+ {
+ // 创建一个可重用固定线程数的线程池
+ ExecutorService pool = Executors.newFixedThreadPool(3);
+
+ // 创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
+ Thread t1 = new MyThread();
+ Thread t2 = new MyThread();
+ Thread t3 = new MyThread();
+ Thread t4 = new MyThread();
+ Thread t5 = new MyThread();
+
+ // 将线程放入池中进行执行
+ pool.execute(t1);
+ pool.execute(t2);
+ pool.execute(t3);
+ pool.execute(t4);
+ pool.execute(t5);
+
+ // 关闭线程池
+ pool.shutdown();
+ }
+}
+
+class MyThread extends Thread
+{
+ @Override
+ public void run()
+ {
+ try
+ {
+ System.out.println(Thread.currentThread().getName() + "正在执行。。。");
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/executor/asyncprocess/ExecutorThreadFactory.java b/basicKnowledge/src/com/xdc/basic/api/thread/executor/asyncprocess/ExecutorThreadFactory.java
new file mode 100644
index 00000000..31f94c44
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/executor/asyncprocess/ExecutorThreadFactory.java
@@ -0,0 +1,19 @@
+package com.xdc.basic.api.thread.executor.asyncprocess;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class ExecutorThreadFactory implements ThreadFactory
+{
+ private static final String THREAD_NAME_PREFIX = "MyThread-";
+
+ private AtomicLong seq = new AtomicLong(0);
+
+ @Override
+ public Thread newThread(Runnable r)
+ {
+ Thread t = new Thread(r);
+ t.setName(THREAD_NAME_PREFIX + seq.getAndIncrement());
+ return t;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/executor/asyncprocess/ThreadExecutor.java b/basicKnowledge/src/com/xdc/basic/api/thread/executor/asyncprocess/ThreadExecutor.java
new file mode 100644
index 00000000..7ce5d666
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/executor/asyncprocess/ThreadExecutor.java
@@ -0,0 +1,37 @@
+package com.xdc.basic.api.thread.executor.asyncprocess;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class ThreadExecutor
+{
+ private ExecutorService threadPool;
+ private static final ThreadExecutor instance = new ThreadExecutor();
+
+ private ThreadExecutor()
+ {
+ threadPool = Executors.newFixedThreadPool(20, new ExecutorThreadFactory());
+ }
+
+ public static ThreadExecutor getInstance()
+ {
+ return instance;
+ }
+
+ public void asyncExec(Runnable task)
+ {
+ threadPool.execute(task);
+ }
+
+ public static void sleepSecond(long second)
+ {
+ try
+ {
+ Thread.sleep(second);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/executor/asyncprocess/abstractProcess.java b/basicKnowledge/src/com/xdc/basic/api/thread/executor/asyncprocess/abstractProcess.java
new file mode 100644
index 00000000..e6ce16d7
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/executor/asyncprocess/abstractProcess.java
@@ -0,0 +1,27 @@
+package com.xdc.basic.api.thread.executor.asyncprocess;
+
+public abstract class abstractProcess
+{
+ public String asyncProcess(final String para)
+ {
+ ThreadExecutor.getInstance().asyncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ process(para);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ });
+ return "success!";
+ }
+
+ abstract void process(String para);
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/flowcontrol/CoutDownLatchTest1.java b/basicKnowledge/src/com/xdc/basic/api/thread/flowcontrol/CoutDownLatchTest1.java
new file mode 100644
index 00000000..9d7ad75a
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/flowcontrol/CoutDownLatchTest1.java
@@ -0,0 +1,39 @@
+package com.xdc.basic.api.thread.flowcontrol;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * 当你启动了一个线程,你需要等它执行结束,此时,CountDownLatch也许是一个很好的选择。
+ *
+ * @author xdc
+ *
+ */
+public class CoutDownLatchTest1
+{
+ public static void main(String[] args) throws InterruptedException
+ {
+ final int COUNT = 10;
+ final CountDownLatch completeLatch = new CountDownLatch(COUNT);
+ for (int i = 0; i < COUNT; ++i)
+ {
+ Thread thread = new Thread("worker thread " + i)
+ {
+ public void run()
+ {
+ System.out.println("子线程开始执行:" + Thread.currentThread().getName());
+ // do something
+ System.out.println("子线程完成执行:" + Thread.currentThread().getName());
+
+ // 计数器减1
+ completeLatch.countDown();
+ }
+ };
+ thread.start();
+ }
+
+ System.out.println("主线程开始等待。。");
+ // 计数减为0时,继续向下执行
+ completeLatch.await();
+ System.out.println("主线程完成等待。。");
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/flowcontrol/CoutDownLatchTest2.java b/basicKnowledge/src/com/xdc/basic/api/thread/flowcontrol/CoutDownLatchTest2.java
new file mode 100644
index 00000000..4cdd7d20
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/flowcontrol/CoutDownLatchTest2.java
@@ -0,0 +1,42 @@
+package com.xdc.basic.api.thread.flowcontrol;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * 当你启动很多线程,你需要这些线程等到通知后才真正开始,CountDownLatch也许是一个很好的选择。
+ *
+ * @author xdc
+ *
+ */
+public class CoutDownLatchTest2
+{
+ public static void main(String[] args) throws InterruptedException
+ {
+ final CountDownLatch startLatch = new CountDownLatch(1);
+ for (int i = 0; i < 10; ++i)
+ {
+ Thread thread = new Thread("worker thread " + i)
+ {
+ public void run()
+ {
+ try
+ {
+ System.out.println("子线程开始等待主线程命令:" + Thread.currentThread().getName());
+ startLatch.await();
+ System.out.println("子线程完成等待主线程命令:" + Thread.currentThread().getName());
+ }
+ catch (InterruptedException e)
+ {
+ return;
+ }
+ // do xxxx
+ }
+ };
+ thread.start();
+ }
+
+ // do xxx
+ System.out.println("主线程马上其他线程可以继续执行了。");
+ startLatch.countDown();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/flowcontrol/CyclicBarrierTest.java b/basicKnowledge/src/com/xdc/basic/api/thread/flowcontrol/CyclicBarrierTest.java
new file mode 100644
index 00000000..e948517b
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/flowcontrol/CyclicBarrierTest.java
@@ -0,0 +1,70 @@
+package com.xdc.basic.api.thread.flowcontrol;
+
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
+/**
+ * 循环障碍,可以用于性能测试
+ *
+ * @author xdc
+ *
+ */
+class CyclicBarrierTest
+{
+ public static void main(String[] args)
+ {
+ int threadCount = 3;
+ final int loopCount = 10;
+
+ final CyclicBarrier barrier = new CyclicBarrier(threadCount, new Runnable()
+ {
+ public void run()
+ {
+ // 等待所有子线程完成
+ collectTestResult();
+ }
+ });
+
+ for (int i = 0; i < threadCount; ++i)
+ {
+ Thread thread = new Thread("test-thread " + i)
+ {
+ public void run()
+ {
+ for (int j = 0; j < loopCount; ++j)
+ {
+ doTest();
+ try
+ {
+ // 通知barrier已经完成
+ System.out.println("子线程已完成:" + Thread.currentThread().getName());
+ barrier.await();
+ }
+ catch (InterruptedException e)
+ {
+ return;
+ }
+ catch (BrokenBarrierException e)
+ {
+ return;
+ }
+ }
+ }
+ };
+ thread.start();
+ }
+
+ }
+
+ private static void doTest()
+ {
+ System.out.println("PerformaceTest.doTest()");
+ /* do xxx */
+ }
+
+ private static void collectTestResult()
+ {
+ System.out.println("PerformaceTest.collectTestResult()");
+ /* do xxx */
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lock/ReentrantLockTest.java b/basicKnowledge/src/com/xdc/basic/api/thread/lock/ReentrantLockTest.java
new file mode 100644
index 00000000..e9b9a3b1
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lock/ReentrantLockTest.java
@@ -0,0 +1,92 @@
+package com.xdc.basic.api.thread.lock;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Lockers 在多线程编程里面一个重要的概念是锁定,如果一个资源是多个线程共享的,为了保证数据的完整性,
+ * 在进行事务性操作时需要将共享资源锁定,这样可以保证在做事务性操作时只有一个线程能对资源进行操作,
+ * 从而保证数据的完整性。在5.0以前,锁定的功能是由Synchronized关键字来实现的。
+ */
+public class ReentrantLockTest
+{
+ public static class LockTest
+ {
+ Lock lock = new ReentrantLock();
+ double value = 0d;
+ int addtimes = 0;
+
+ /**
+ * 增加value的值,该方法的操作分为2步,而且相互依赖,必须实现在一个事务中
+ * 所以该方法必须同步,以前的做法是在方法声明中使用Synchronized关键字。
+ */
+ public void addValue(double v)
+ {
+ lock.lock();// 取得锁
+ try
+ {
+ System.out.println("ReentrantLockTest.LockTest.addValue()");
+ Thread.sleep(1000);
+ this.value += v;
+ this.addtimes++;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ lock.unlock();// 释放锁
+ }
+ }
+
+ public double getValue()
+ {
+ System.out.println("ReentrantLockTest.LockTest.getValue()");
+ return this.value;
+ }
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ final LockTest lockTest = new LockTest();
+
+ // 新建任务1,调用lockTest的addValue方法
+ Runnable task1 = new Runnable()
+ {
+ public void run()
+ {
+ lockTest.addValue(55.55);
+ }
+ };
+ // 新建任务2,调用lockTest的getValue方法
+ Runnable task2 = new Runnable()
+ {
+ public void run()
+ {
+ System.out.println("value: " + lockTest.getValue());
+ }
+ };
+
+ ExecutorService cachedService = Executors.newCachedThreadPool();
+
+ Future> future = null;
+ // 同时执行任务1三次,由于addValue方法使用了锁机制,所以,实质上会顺序执行
+ for (int i = 0; i < 3; i++)
+ {
+ future = cachedService.submit(task1);
+ }
+ // 等待最后一个任务1被执行完
+ future.get();
+
+ // 再执行任务2,输出结果
+ future = cachedService.submit(task2);
+ // 等待任务2执行完后,关闭任务执行服务
+ future.get();
+
+ cachedService.shutdownNow();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lock/ReentrantReadWriteLockTest.java b/basicKnowledge/src/com/xdc/basic/api/thread/lock/ReentrantReadWriteLockTest.java
new file mode 100644
index 00000000..4cc5d39f
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lock/ReentrantReadWriteLockTest.java
@@ -0,0 +1,140 @@
+package com.xdc.basic.api.thread.lock;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * 读写分离锁测试
+ * Lockers 在多线程编程里面一个重要的概念是锁定,如果一个资源是多个线程共享的,为了保证数据的完整性,
+ * 在进行事务性操作时需要将共享资源锁定,这样可以保证在做事务性操作时只有一个线程能对资源进行操作,
+ * 从而保证数据的完整性。在5.0以前,锁定的功能是由Synchronized关键字来实现的。
+ */
+public class ReentrantReadWriteLockTest
+{
+ /**
+ * ReadWriteLock内置两个Lock,一个是读的Lock,一个是写的Lock。
+ * 多个线程可同时得到读的Lock,但只有一个线程能得到写的Lock,
+ * 而且写的Lock被锁定后,任何线程都不能得到Lock。ReadWriteLock提供的方法有: readLock(): 返回一个读的lock
+ * writeLock(): 返回一个写的lock, 此lock是排他的。 ReadWriteLockTest很适合处理类似文件的读写操作。
+ * 读的时候可以同时读,但不能写;写的时候既不能同时写也不能读。
+ *
+ * 总结:
+ * 先 后
+ * 读 读 不阻塞
+ * 读 写 阻塞
+ * 写 读 阻塞
+ * 写 写 阻塞
+ */
+ public static class ReadWriteLockTest
+ {
+ ReadWriteLock lock = new ReentrantReadWriteLock();
+ double value = 0d;
+ int addtimes = 0;
+
+ /**
+ * 增加value的值,不允许多个线程同时进入该方法
+ */
+ public void addValue(double v)
+ {
+ // 得到writeLock并锁定
+ lock.writeLock().lock();
+ try
+ {
+ System.out.println("ReentrantReadWriteLockTest.ReadWriteLockTest.addValue()");
+ Thread.sleep(1000);
+ // 做写的工作
+ this.value += v;
+ this.addtimes++;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ // 释放writeLock锁
+ lock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * 获得信息。当有线程在调用addValue方法时,getInfo得到的信息可能是不正确的。
+ * 所以,也必须保证该方法在被调用时,没有方法在调用addValue方法。
+ */
+ public String getInfo()
+ {
+ // 得到readLock并锁定
+ lock.readLock().lock();
+ try
+ {
+ System.out.println("ReentrantReadWriteLockTest.ReadWriteLockTest.getInfo()");
+ Thread.sleep(1000);
+ // 做读的工作
+ return this.value + " : " + this.addtimes;
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ // 释放readLock
+ lock.readLock().unlock();
+ }
+ return null;
+ }
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ final ReadWriteLockTest readWriteLockTest = new ReadWriteLockTest();
+
+ // 新建任务1,调用lockTest的addValue方法
+ Runnable task1 = new Runnable()
+ {
+ public void run()
+ {
+ readWriteLockTest.addValue(55.55);
+ }
+ };
+ // 新建任务2,调用lockTest的getValue方法
+ Runnable task2 = new Runnable()
+ {
+ public void run()
+ {
+ System.out.println("info: " + readWriteLockTest.getInfo());
+ }
+ };
+
+ // 新建任务执行服务
+ ExecutorService cachedService = Executors.newCachedThreadPool();
+
+ Future> future = null;
+
+ // 同时执行5个任务,其中前2个任务是task1,后两个任务是task2
+ for (int i = 0; i < 2; i++)
+ {
+ future = cachedService.submit(task1);
+ }
+ for (int i = 0; i < 2; i++)
+ {
+ future = cachedService.submit(task2);
+ }
+ // 最后一个任务是task1
+ future = cachedService.submit(task1);
+
+ // 这5个任务的执行顺序应该是:
+ // 第一个task1先执行,第二个task1再执行;这是因为不能同时写,所以必须等。
+ // 然后2个task2同时执行;这是因为在写的时候,就不能读,所以都等待写结束,
+ // 又因为可以同时读,所以它们同时执行
+ // 最后一个task1再执行。这是因为在读的时候,也不能写,所以必须等待读结束后,才能写。
+
+ // 等待最后一个task_2被执行完
+ future.get();
+ cachedService.shutdownNow();
+
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/BankService.java b/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/BankService.java
new file mode 100644
index 00000000..2d0a8e05
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/BankService.java
@@ -0,0 +1,92 @@
+package com.xdc.basic.api.thread.lock.splitinglock;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class BankService
+{
+ private Map bank = new HashMap();
+ private SplitingLock lock = new SplitingLock();
+
+ public BankService()
+ {
+ super();
+ }
+
+ public Map getBank()
+ {
+ return bank;
+ }
+
+ /**
+ * 存钱
+ *
+ * @param money
+ */
+ public void deposit(String userId, int money)
+ {
+ lock.lock(userId);
+ try
+ {
+ User user = bank.get(userId);
+ if (user == null)
+ {
+ user = new User(userId, 0);
+ bank.put(userId, user);
+ }
+
+ System.out.println(Thread.currentThread().getName() + " : " + userId + " 开始存入 " + money + "元。当前值:" + user);
+ user.deposit(money);
+ System.out.println(Thread.currentThread().getName() + " : " + userId + " 完成存入 " + money + "元。当前值:" + user);
+
+ try
+ {
+ Thread.sleep(10L);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ finally
+ {
+ lock.unlock(userId);
+ }
+ }
+
+ /**
+ * 取钱
+ *
+ * @param money
+ */
+ public void withdrawing(String userId, int money)
+ {
+ lock.lock(userId);
+ try
+ {
+ User user = bank.get(userId);
+ if (user == null)
+ {
+ user = new User(userId, 0);
+ bank.put(userId, user);
+ }
+
+ System.out.println(Thread.currentThread().getName() + " : " + userId + " 开始取出 " + money + "元。当前值:" + user);
+ user.withdrawing(money);
+ System.out.println(Thread.currentThread().getName() + " : " + userId + " 开始取出 " + money + "元。当前值:" + user);
+
+ try
+ {
+ Thread.sleep(10L);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ finally
+ {
+ lock.unlock(userId);
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/SplitingLock.java b/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/SplitingLock.java
new file mode 100644
index 00000000..02c1f74b
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/SplitingLock.java
@@ -0,0 +1,80 @@
+package com.xdc.basic.api.thread.lock.splitinglock;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 分拆锁, 根据资源id,通过维护相应的锁,实现更细化的控制,资源之间不会干扰
+ *
+ * @author xdc
+ *
+ */
+public class SplitingLock
+{
+ private Map locks = new HashMap();
+
+ void lock(T key)
+ {
+ CountLock lock = null;
+ synchronized (locks)
+ {
+ lock = locks.get(key);
+ if (lock == null)
+ {
+ lock = new CountLock();
+ locks.put(key, lock);
+ }
+ lock.increaseCount();
+ }
+
+ lock.getLock().lock();
+ }
+
+ void unlock(T key)
+ {
+ CountLock lock = locks.get(key);
+ if (lock == null)
+ {
+ return;
+ }
+ lock.getLock().unlock();
+
+ synchronized (locks)
+ {
+ lock.decreaseCount();
+ if (lock.getCount() == 0)
+ {
+ locks.remove(key);
+ }
+ }
+ }
+
+ class CountLock
+ {
+ private Lock lock = new ReentrantLock();
+
+ private volatile int count = 0;
+
+ public Lock getLock()
+ {
+ return lock;
+ }
+
+ public int getCount()
+ {
+ return count;
+ }
+
+ void increaseCount()
+ {
+ this.count++;
+ }
+
+ void decreaseCount()
+ {
+ this.count--;
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/SplitingLockTest.java b/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/SplitingLockTest.java
new file mode 100644
index 00000000..c34a0fc2
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/SplitingLockTest.java
@@ -0,0 +1,72 @@
+package com.xdc.basic.api.thread.lock.splitinglock;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+public class SplitingLockTest
+{
+ public static void main(String[] args) throws InterruptedException, ExecutionException
+ {
+ // 此处若改为使用Executors.newCachedThreadPool(),下面的其他代码保持不变,不到一会内存将被占满,机器卡死。
+ // 这就能看出了两种方法的不同。
+ ExecutorService pool = Executors.newFixedThreadPool(20);
+
+ final BankService bankService = new BankService();
+
+ List> futures = new ArrayList>();
+ for (int i = 0; i < 100000; i++)
+ {
+ Future> future = pool.submit(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ bankService.deposit("xdc", 100);
+ }
+ });
+ futures.add(future);
+
+ future = pool.submit(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ bankService.withdrawing("xdc", 100);
+ }
+ });
+ futures.add(future);
+
+ future = pool.submit(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ bankService.deposit("gx", 100);
+ }
+ });
+ futures.add(future);
+
+ future = pool.submit(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ bankService.withdrawing("gx", 100);
+ }
+ });
+ futures.add(future);
+ }
+
+ for (Future> future : futures)
+ {
+ future.get();
+ }
+ System.out.println("最终结果: " + bankService.getBank());
+
+ pool.shutdown();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/User.java b/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/User.java
new file mode 100644
index 00000000..ada8ad6d
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lock/splitinglock/User.java
@@ -0,0 +1,68 @@
+package com.xdc.basic.api.thread.lock.splitinglock;
+
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+public class User
+{
+ private String userId;
+ private long money;
+
+ public User()
+ {
+ super();
+ }
+
+ public User(String userId, long money)
+ {
+ super();
+ this.userId = userId;
+ this.money = money;
+ }
+
+ public String getUserId()
+ {
+ return userId;
+ }
+
+ public void setUserId(String userId)
+ {
+ this.userId = userId;
+ }
+
+ public long getMoney()
+ {
+ return money;
+ }
+
+ public void setMoney(long money)
+ {
+ this.money = money;
+ }
+
+ /**
+ * 存钱
+ *
+ * @param money
+ */
+ public void deposit(int money)
+ {
+ this.money += money;
+ }
+
+ /**
+ * 取钱
+ *
+ * @param money
+ */
+ public void withdrawing(int money)
+ {
+ this.money -= money;
+ }
+
+ @Override
+ public String toString()
+ {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/beanmanager/BeanManagerConcurrentMap.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/beanmanager/BeanManagerConcurrentMap.java
new file mode 100644
index 00000000..d27ca6dd
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/beanmanager/BeanManagerConcurrentMap.java
@@ -0,0 +1,32 @@
+package com.xdc.basic.api.thread.lockfree.beanmanager;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * ConcurrentHashMap并没有实现Lock-Free,只是使用了分离锁的办法使得能够支持多个Writer并发。
+ * ConcurrentHashMap需要使用更多的内存。
+ *
+ * @author xdc
+ *
+ */
+public class BeanManagerConcurrentMap
+{
+ private ConcurrentMap map = new ConcurrentHashMap();
+
+ public Object getBean(String key)
+ {
+ Object bean = map.get(key);
+ if (bean == null)
+ {
+ map.putIfAbsent(key, createBean(key));
+ bean = map.get(key);
+ }
+ return bean;
+ }
+
+ private Object createBean(String key)
+ {
+ return key;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/beanmanager/BeanManagerSync.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/beanmanager/BeanManagerSync.java
new file mode 100644
index 00000000..051440ff
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/beanmanager/BeanManagerSync.java
@@ -0,0 +1,28 @@
+package com.xdc.basic.api.thread.lockfree.beanmanager;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class BeanManagerSync
+{
+ private Map map = new HashMap();
+
+ public Object getBean(String key)
+ {
+ synchronized (map)
+ {
+ Object bean = map.get(key);
+ if (bean == null)
+ {
+ map.put(key, createBean(key));
+ bean = map.get(key);
+ }
+ return bean;
+ }
+ }
+
+ private Object createBean(String key)
+ {
+ return key;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/counter/CounterAtomicInteger.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/counter/CounterAtomicInteger.java
new file mode 100644
index 00000000..71e677a3
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/counter/CounterAtomicInteger.java
@@ -0,0 +1,25 @@
+package com.xdc.basic.api.thread.lockfree.counter;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 这是由硬件提供原子操作指令实现的。在非激烈竞争的情况下,开销更小,速度更快。Java.util.concurrent中实现的原子操作类包括:
+ * AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference
+ *
+ * @author xdc
+ *
+ */
+public class CounterAtomicInteger
+{
+ private AtomicInteger count = new AtomicInteger();
+
+ public void increment()
+ {
+ count.incrementAndGet();
+ }
+
+ public int getCount()
+ {
+ return count.get();
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/counter/CounterSync.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/counter/CounterSync.java
new file mode 100644
index 00000000..06381e32
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/counter/CounterSync.java
@@ -0,0 +1,16 @@
+package com.xdc.basic.api.thread.lockfree.counter;
+
+public class CounterSync
+{
+ private volatile int count = 0;
+
+ public synchronized void increment()
+ {
+ count++;
+ }
+
+ public int getCount()
+ {
+ return count;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/optimisticlock/SequenceDao.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/optimisticlock/SequenceDao.java
new file mode 100644
index 00000000..8ca4474f
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/optimisticlock/SequenceDao.java
@@ -0,0 +1,27 @@
+package com.xdc.basic.api.thread.lockfree.database.optimisticlock;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
+
+@SuppressWarnings("deprecation")
+public class SequenceDao extends SqlMapClientDaoSupport
+{
+ public boolean compareAndSet(String name, int value, int expect)
+ {
+ Map parameters = new HashMap();
+ parameters.put("name", name);
+ parameters.put("value", value);
+ parameters.put("expect", expect);
+ // UPDATE t_sequence SET value = #value# WHERE name = #name# AND value = #expect#
+ int updateCount = getSqlMapClientTemplate().update("Sequence.compareAndSet", parameters);
+ return updateCount == 1;
+ }
+
+ public int getValue(String sequenceName)
+ {
+ // 在数据库中查询当前值
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/optimisticlock/SequenceService.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/optimisticlock/SequenceService.java
new file mode 100644
index 00000000..296be669
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/optimisticlock/SequenceService.java
@@ -0,0 +1,29 @@
+package com.xdc.basic.api.thread.lockfree.database.optimisticlock;
+
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * CAS用于更新数据库-乐观锁
+ *
+ * @author xdc
+ *
+ */
+public class SequenceService
+{
+ private SequenceDao dao;
+
+ // 注意,乐观锁时必须使用:@Transactional(propagation = Propagation.NOT_SUPPORTED)
+ @Transactional(propagation = Propagation.NOT_SUPPORTED)
+ public synchronized void increment(String sequenceName)
+ {
+ for (;;)
+ {
+ int value = dao.getValue(sequenceName);
+ if (dao.compareAndSet(sequenceName, value + 1, value))
+ {
+ break;
+ }
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/pessimisticlock/SequenceDao.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/pessimisticlock/SequenceDao.java
new file mode 100644
index 00000000..e14c9cdf
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/pessimisticlock/SequenceDao.java
@@ -0,0 +1,25 @@
+package com.xdc.basic.api.thread.lockfree.database.pessimisticlock;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
+
+@SuppressWarnings("deprecation")
+public class SequenceDao extends SqlMapClientDaoSupport
+{
+ public int getValueForUpdate(String name)
+ {
+ // SELECT value FROM t_sequenceWHERE name = #name# FOR UPDATE
+ return (Integer) getSqlMapClientTemplate().queryForObject("Sequence.getValueForUpdate", name);
+ }
+
+ public void set(String name, int value)
+ {
+ Map parameters = new HashMap();
+ parameters.put("name", name);
+ parameters.put("value", value);
+ // UPDATE t_sequence SET value = #value# WHERE name = #name#
+ getSqlMapClientTemplate().update("Sequence.set", parameters);
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/pessimisticlock/SequenceService.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/pessimisticlock/SequenceService.java
new file mode 100644
index 00000000..52b7faed
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/database/pessimisticlock/SequenceService.java
@@ -0,0 +1,22 @@
+package com.xdc.basic.api.thread.lockfree.database.pessimisticlock;
+
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 使用悲观锁版本
+ *
+ * @author xdc
+ *
+ */
+public class SequenceService
+{
+ private SequenceDao dao;
+
+ @Transactional(propagation = Propagation.REQUIRED)
+ public synchronized void increment2(String sequenceName)
+ {
+ int value = dao.getValueForUpdate(sequenceName);
+ dao.set(sequenceName, value + 1);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/databuffer/DataBufferBlockingQueue.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/databuffer/DataBufferBlockingQueue.java
new file mode 100644
index 00000000..4e04612b
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/databuffer/DataBufferBlockingQueue.java
@@ -0,0 +1,82 @@
+package com.xdc.basic.api.thread.lockfree.databuffer;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.apache.commons.lang3.RandomStringUtils;
+
+/**
+ * http://www.fengfly.com/plus/view-191064-1.html
+ *
+ * @author xdc
+ *
+ */
+public class DataBufferBlockingQueue
+{
+ public static void main(String[] args)
+ {
+ BlockingQueue dataQueue = new ArrayBlockingQueue(1, true);
+
+ ExecutorService pool = Executors.newCachedThreadPool();
+ pool.submit(new Producer(dataQueue));
+ pool.submit(new Consumer(dataQueue));
+
+ // 执行后关闭线程池
+ pool.shutdown();
+ }
+}
+
+class Producer implements Runnable
+{
+ private BlockingQueue dataQueue;
+
+ public Producer(BlockingQueue dataQueue)
+ {
+ this.dataQueue = dataQueue;
+ }
+
+ public void run()
+ {
+ try
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ String data = RandomStringUtils.randomAlphanumeric(6);
+ dataQueue.put(data);
+ System.out.println(data + " is putted!");
+ }
+
+ dataQueue.put("END");
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
+
+class Consumer implements Runnable
+{
+ private BlockingQueue dataQueue;
+
+ public Consumer(BlockingQueue dataQueue)
+ {
+ this.dataQueue = dataQueue;
+ }
+
+ public void run()
+ {
+ String msg = null;
+ try
+ {
+ while (!((msg = dataQueue.take()).equals("END")))
+ System.out.println(msg + " is token!");
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/databuffer/DataBufferSync.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/databuffer/DataBufferSync.java
new file mode 100644
index 00000000..c2913d90
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/databuffer/DataBufferSync.java
@@ -0,0 +1,142 @@
+package com.xdc.basic.api.thread.lockfree.databuffer;
+
+import java.util.Vector;
+
+import org.apache.commons.lang3.RandomStringUtils;
+
+public class DataBufferSync
+{
+ Vector dataBuffer = new Vector(); // 数据缓冲区
+ final int MAX_SIZE = 3; // 设置缓冲区大小
+
+ void addData()
+ {
+ synchronized (dataBuffer)
+ {
+ String name = Thread.currentThread().getName();
+ System.out.println(name + " enter addData()");
+
+ while (dataBuffer.size() == MAX_SIZE)
+ {
+ try
+ {
+ System.out.println(name + " data buffer is full, try to wait");
+ dataBuffer.wait();
+ System.out.println(name + " wake up, continue to add data");
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ String data = "value-" + RandomStringUtils.randomNumeric(2);
+ dataBuffer.add(data);
+ dataBuffer.notifyAll();
+
+ System.out.println(name + " adds " + data + ", ramains " + dataBuffer.size());
+ System.out.println(name + " leave addData()");
+ }
+ }
+
+ void removeData()
+ {
+ synchronized (dataBuffer)
+ {
+ String name = Thread.currentThread().getName();
+ System.out.println(name + " enter removeData()");
+
+ while (dataBuffer.size() == 0)
+ {
+ try
+ {
+ // 临时释放锁,并阻塞当前线程,好让其他使用同一把锁的线程有机会执行.
+ // 其他线程在执行到一定地方后用notify()通知wait()的线程,
+ // 待notify()所在的同步块运行完之后,wait所在的线程就可以继续执行.
+ System.out.println(name + " data buffer is empty, try to wait");
+ dataBuffer.wait();
+ System.out.println(name + " wake up, continue to remove data");
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ String data = dataBuffer.remove(0);
+ dataBuffer.notifyAll();
+
+ System.out.println(name + " removes " + data + ", ramains " + dataBuffer.size());
+ System.out.println(name + " leave removeData()");
+ }
+ }
+
+ private void start()
+ {
+ new Consumer(this).start();
+ new Consumer(this).start();
+ new Consumer(this).start();
+ new Producer(this).start();
+ }
+
+ public static void main(String[] args)
+ {
+ DataBufferSync wn = new DataBufferSync();
+ wn.start();
+ }
+
+ class Producer extends Thread
+ {
+ DataBufferSync synObject;
+
+ Producer(DataBufferSync synObject)
+ {
+ this.synObject = synObject;
+ }
+
+ public void run()
+ {
+ String name = getName();
+ while (true)
+ {
+ System.out.println(name + " try to add Data ...");
+ synObject.addData();
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ class Consumer extends Thread
+ {
+ DataBufferSync synObject;
+
+ Consumer(DataBufferSync synObject)
+ {
+ this.synObject = synObject;
+ }
+
+ public void run()
+ {
+ String name = getName();
+ while (true)
+ {
+ System.out.println(name + " try to remove Data ...");
+ synObject.removeData();
+ try
+ {
+ Thread.sleep(4000);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/engine/EngineCopyOnWriteArrayList.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/engine/EngineCopyOnWriteArrayList.java
new file mode 100644
index 00000000..b30cdee7
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/engine/EngineCopyOnWriteArrayList.java
@@ -0,0 +1,25 @@
+package com.xdc.basic.api.thread.lockfree.engine;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import com.google.common.util.concurrent.ServiceManager.Listener;
+
+class EngineCopyOnWriteArrayList
+{
+ private List listeners = new CopyOnWriteArrayList();
+
+ public boolean addListener(Listener listener)
+ {
+ return listeners.add(listener);
+ }
+
+ @SuppressWarnings("unused")
+ public void doXXX()
+ {
+ for (Listener listener : listeners)
+ {
+ // listener.handle();
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/engine/EngineSync.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/engine/EngineSync.java
new file mode 100644
index 00000000..2cd9de39
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/engine/EngineSync.java
@@ -0,0 +1,31 @@
+package com.xdc.basic.api.thread.lockfree.engine;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.common.util.concurrent.ServiceManager.Listener;
+
+class Engine
+{
+ private List listeners = new ArrayList();
+
+ public boolean addListener(Listener listener)
+ {
+ synchronized (listeners)
+ {
+ return listeners.add(listener);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public void doXXX()
+ {
+ synchronized (listeners)
+ {
+ for (Listener listener : listeners)
+ {
+ // listener.handle();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/maxholder/MaxHolderCAS.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/maxholder/MaxHolderCAS.java
new file mode 100644
index 00000000..dde2d9f1
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/maxholder/MaxHolderCAS.java
@@ -0,0 +1,42 @@
+package com.xdc.basic.api.thread.lockfree.maxholder;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * LockFree算法,不需要加锁。通常都是三个部分组成: ①循环 ②CAS (CompareAndSet) ③回退
+ *
+ * @author xdc
+ *
+ */
+public class MaxHolderCAS
+{
+ private AtomicInteger max = new AtomicInteger();
+
+ public void set(int value)
+ {
+ for (;;)
+ {
+ int current = max.get();
+ if (value > current)
+ {
+ if (max.compareAndSet(current, value))
+ {
+ break;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ public int getMax()
+ {
+ return max.get();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/maxholder/MaxHolderSync.java b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/maxholder/MaxHolderSync.java
new file mode 100644
index 00000000..64e90c12
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/lockfree/maxholder/MaxHolderSync.java
@@ -0,0 +1,19 @@
+package com.xdc.basic.api.thread.lockfree.maxholder;
+
+public class MaxHolderSync
+{
+ private volatile int max = 0;
+
+ public synchronized void set(int value)
+ {
+ if (value > max)
+ {
+ max = value;
+ }
+ }
+
+ public int getMax()
+ {
+ return max;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo1/RunnableImpl.java b/basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo1/RunnableImpl.java
new file mode 100644
index 00000000..893e02e7
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo1/RunnableImpl.java
@@ -0,0 +1,25 @@
+package com.xdc.basic.api.thread.synclock.demo1;
+
+class RunnableImpl implements Runnable
+{
+ // 火车票张数
+ int i = 100000;
+
+ public void run()
+ {
+ while (true)
+ {
+ synchronized (this)
+ {
+ // 如果张数小于等于0,就没有了,不买了
+ if (i <= 0)
+ {
+ break;
+ }
+ System.out.println(Thread.currentThread().getName() + "买到了一张火车票,编号:" + i);
+ i--;
+ Thread.yield();
+ }
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/java4android/thread/implrunable/Test.java b/basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo1/Test.java
similarity index 84%
rename from basicKnowledge/src/com/xdc/basic/java4android/thread/implrunable/Test.java
rename to basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo1/Test.java
index c7e115c2..0e799f96 100644
--- a/basicKnowledge/src/com/xdc/basic/java4android/thread/implrunable/Test.java
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo1/Test.java
@@ -1,20 +1,20 @@
-package com.xdc.basic.java4android.thread.implrunable;
-
-class Test
-{
- public static void main(String[] args)
- {
- // 生成一个Runnable接口的实现类的对象
- RunnableImpl r = new RunnableImpl();
- // 生成一个Thread对象,并将Runnalbe接口的实
- // 现类的对象作为参数传递给该Thread对象
-
- Thread t = new Thread(r);
- t.setName("t1");
- t.start();
-
- Thread t2 = new Thread(r);
- t2.setName("t2");
- t2.start();
- }
-}
+package com.xdc.basic.api.thread.synclock.demo1;
+
+class Test
+{
+ public static void main(String[] args)
+ {
+ // 生成一个Runnable接口的实现类的对象
+ RunnableImpl r = new RunnableImpl();
+ // 生成一个Thread对象,并将Runnalbe接口的实
+ // 现类的对象作为参数传递给该Thread对象
+
+ Thread t = new Thread(r);
+ t.setName("t1");
+ t.start();
+
+ Thread t2 = new Thread(r);
+ t2.setName("t2");
+ t2.start();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo2/Person.java b/basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo2/Person.java
new file mode 100644
index 00000000..b452012c
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo2/Person.java
@@ -0,0 +1,104 @@
+package com.xdc.basic.api.thread.synclock.demo2;
+
+public class Person
+{
+ public void listenMusic()
+ {
+ System.out.println("--------------------------------- I'm listening music.");
+ sleepHalfSecond();
+ }
+
+ public synchronized void study()
+ {
+ System.out.println("I will start to study.");
+ sleep1Second();
+
+ for (int i = 0; i < 5; i++)
+ {
+ System.out.println("+++++++++++++++++++++++++++++++++ I'm studying.");
+ sleep1Second();
+ }
+
+ System.out.println("I have finished my study.");
+ sleep1Second();
+ }
+
+ public synchronized void sleep()
+ {
+ System.out.println("I will start to sleep.");
+ sleep1Second();
+
+ for (int i = 0; i < 5; i++)
+ {
+ System.out.println("================================= I'm sleepping. zzZ...");
+ sleep1Second();
+ }
+
+ System.out.println("I have finished my sleep.");
+ sleep1Second();
+ }
+
+ public void playFootball()
+ {
+ System.out.println("I will start to play football.");
+ sleep1Second();
+
+ synchronized (this)
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ System.out.println("********************************* I'm playing football.");
+ sleep1Second();
+ }
+ }
+
+ System.out.println("I have finished playing football.");
+ sleep1Second();
+ }
+
+ public void playBasketball()
+ {
+ System.out.println("I will start to play basketball.");
+ sleep1Second();
+
+ synchronized (this)
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& I am playing basketball.");
+ sleep1Second();
+ }
+ }
+
+ System.out.println("I have finished playing basketball.");
+ sleep1Second();
+ }
+
+ private void sleep1Second()
+ {
+ try
+ {
+ Thread.sleep(1000L);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private void sleepHalfSecond()
+ {
+ try
+ {
+ Thread.sleep(500L);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ // Ps: synchronized void f() { /* body */ }
+ // 和 void f() { synchronized(this) { /* body */ } }
+ // 是完全等价的。
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo2/syncTest.java b/basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo2/syncTest.java
new file mode 100644
index 00000000..28059ebd
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/thread/synclock/demo2/syncTest.java
@@ -0,0 +1,76 @@
+package com.xdc.basic.api.thread.synclock.demo2;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class syncTest
+{
+
+ public static void main(String[] args)
+ {
+ ExecutorService pool = Executors.newCachedThreadPool();
+
+ final Person person = new Person();
+
+ pool.execute(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ while (true)
+ {
+ person.listenMusic();
+ }
+ }
+ });
+
+ pool.execute(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ while (true)
+ {
+ person.study();
+ }
+ }
+ });
+
+ pool.execute(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ while (true)
+ {
+ person.sleep();
+ }
+ }
+ });
+
+ pool.execute(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ while (true)
+ {
+ person.playFootball();
+ }
+ }
+ });
+
+ pool.execute(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ while (true)
+ {
+ person.playBasketball();
+ }
+ }
+ });
+ }
+
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/xml/Student.java b/basicKnowledge/src/com/xdc/basic/api/xml/Student.java
new file mode 100644
index 00000000..14d175d1
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/xml/Student.java
@@ -0,0 +1,81 @@
+package com.xdc.basic.api.xml;
+
+public class Student
+{
+ private String id;
+ private String name;
+ private String age;
+ private String sex;
+ private String address;
+
+ public Student()
+ {
+ super();
+ }
+
+ public Student(String id, String name, String age, String sex, String address)
+ {
+ super();
+ this.id = id;
+ this.name = name;
+ this.age = age;
+ this.sex = sex;
+ this.address = address;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ public void setId(String id)
+ {
+ this.id = id;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public String getAge()
+ {
+ return age;
+ }
+
+ public void setAge(String age)
+ {
+ this.age = age;
+ }
+
+ public String getSex()
+ {
+ return sex;
+ }
+
+ public void setSex(String sex)
+ {
+ this.sex = sex;
+ }
+
+ public String getAddress()
+ {
+ return address;
+ }
+
+ public void setAddress(String address)
+ {
+ this.address = address;
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("Student [id=%s, name=%s, age=%s, sex=%s, address=%s]", id, name, age, sex, address);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/xml/X1_DomTest.java b/basicKnowledge/src/com/xdc/basic/api/xml/X1_DomTest.java
new file mode 100644
index 00000000..4827b81a
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/xml/X1_DomTest.java
@@ -0,0 +1,53 @@
+package com.xdc.basic.api.xml;
+
+import java.io.File;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import com.xdc.basic.skills.GetCurPath;
+
+public class X1_DomTest
+{
+ public static void main(String arge[])
+ {
+ String curPath = GetCurPath.getCurPath();
+ File file = new File(curPath + "students.xml");
+ try
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document doc = builder.parse(file);
+
+ Element element = doc.getDocumentElement();
+ NodeList nodeList = element.getElementsByTagName("student");
+ for (int i = 0; i < nodeList.getLength(); i++)
+ {
+ Element student = (Element) nodeList.item(i);
+ String id = student.getAttribute("id");
+
+ Element studentName = (Element) student.getElementsByTagName("name").item(0);
+ String name = studentName.getFirstChild().getNodeValue();
+
+ Element studentAge = (Element) student.getElementsByTagName("age").item(0);
+ String age = studentAge.getFirstChild().getNodeValue();
+
+ Element studentSex = (Element) student.getElementsByTagName("sex").item(0);
+ String sex = studentSex.getFirstChild().getNodeValue();
+
+ Element studentAddress = (Element) student.getElementsByTagName("address").item(0);
+ String address = studentAddress.getFirstChild().getNodeValue();
+
+ System.out.println(new Student(id, name, age, sex, address));
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/xml/X2_SaxTest.java b/basicKnowledge/src/com/xdc/basic/api/xml/X2_SaxTest.java
new file mode 100644
index 00000000..c207c6a7
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/xml/X2_SaxTest.java
@@ -0,0 +1,27 @@
+package com.xdc.basic.api.xml;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.helpers.DefaultHandler;
+
+import com.xdc.basic.skills.GetCurPath;
+
+public class X2_SaxTest extends DefaultHandler
+{
+ public static void main(String[] args) throws Exception
+ {
+ String curPath = GetCurPath.getCurPath();
+ InputSource is = new InputSource(curPath + "students.xml");
+ SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+ SAXParser parser = parserFactory.newSAXParser();
+ X2_StudentHandler studentHandler = new X2_StudentHandler();
+ parser.parse(is, studentHandler);
+
+ for (Student student : studentHandler.getStudentList())
+ {
+ System.out.println(student);
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/xml/X2_StudentHandler.java b/basicKnowledge/src/com/xdc/basic/api/xml/X2_StudentHandler.java
new file mode 100644
index 00000000..09c315ce
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/xml/X2_StudentHandler.java
@@ -0,0 +1,82 @@
+package com.xdc.basic.api.xml;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class X2_StudentHandler extends DefaultHandler
+{
+ private Student newStudent;
+ private String curTag;
+ private List studentList;
+
+ public List getStudentList()
+ {
+ return studentList;
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException
+ {
+ String data = new String(ch, start, length);
+ if (null != curTag)
+ {
+ if ("name".equalsIgnoreCase(curTag))
+ {
+ newStudent.setName(data);
+ }
+ else if ("age".equalsIgnoreCase(curTag))
+ {
+ newStudent.setAge(data);
+ }
+ else if ("sex".equalsIgnoreCase(curTag))
+ {
+ newStudent.setSex(data);
+ }
+ else if ("address".equalsIgnoreCase(curTag))
+ {
+ newStudent.setAddress(data);
+ }
+ }
+ }
+
+ @Override
+ public void startDocument() throws SAXException
+ {
+ studentList = new ArrayList();
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException
+ {
+ if ("student".equals(name))
+ {
+ newStudent = new Student();
+ if (attributes != null)
+ {
+ newStudent.setId(attributes.getValue("id"));
+ }
+ }
+ curTag = name;
+ }
+
+ @Override
+ public void endDocument() throws SAXException
+ {
+
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String name) throws SAXException
+ {
+ if ("student".equalsIgnoreCase(name))
+ {
+ studentList.add(newStudent);
+ newStudent = null;
+ }
+ curTag = null;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/xml/X3_JdomTest.java b/basicKnowledge/src/com/xdc/basic/api/xml/X3_JdomTest.java
new file mode 100644
index 00000000..8b5ed98c
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/xml/X3_JdomTest.java
@@ -0,0 +1,41 @@
+package com.xdc.basic.api.xml;
+
+import java.io.File;
+import java.util.List;
+
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.input.SAXBuilder;
+
+import com.xdc.basic.skills.GetCurPath;
+
+public class X3_JdomTest
+{
+ public static void main(String arge[])
+ {
+ String curPath = GetCurPath.getCurPath();
+ File file = new File(curPath + "students.xml");
+ try
+ {
+ SAXBuilder builder = new SAXBuilder();
+ Document doc = builder.build(file);
+ Element root = doc.getRootElement();
+ List allChildren = root.getChildren();
+
+ for (Element element : allChildren)
+ {
+ String id = element.getAttribute("id").getValue();
+ String name = element.getChild("name").getText();
+ String age = element.getChild("age").getText();
+ String sex = element.getChild("sex").getText();
+ String address = element.getChild("address").getText();
+
+ System.out.println(new Student(id, name, age, sex, address));
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/api/xml/X4_Dom4jTest.java b/basicKnowledge/src/com/xdc/basic/api/xml/X4_Dom4jTest.java
new file mode 100644
index 00000000..c00bdc84
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/xml/X4_Dom4jTest.java
@@ -0,0 +1,43 @@
+package com.xdc.basic.api.xml;
+
+import java.io.File;
+import java.util.List;
+
+import org.dom4j.Document;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+
+import com.xdc.basic.skills.GetCurPath;
+
+public class X4_Dom4jTest
+{
+ public static void main(String arge[])
+ {
+ String curPath = GetCurPath.getCurPath();
+ File file = new File(curPath + "students.xml");
+ try
+ {
+ SAXReader reader = new SAXReader();
+ Document doc = reader.read(file);
+ Element root = doc.getRootElement();
+ List> elements = root.elements("student");
+
+ for (Object object : elements)
+ {
+ Element element = (Element) object;
+
+ String id = element.attribute("id").getValue();
+ String name = element.element("name").getText();
+ String age = element.element("age").getText();
+ String sex = element.element("sex").getText();
+ String address = element.element("address").getText();
+
+ System.out.println(new Student(id, name, age, sex, address));
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/xml/X5_xmlPullTest.java b/basicKnowledge/src/com/xdc/basic/api/xml/X5_xmlPullTest.java
new file mode 100644
index 00000000..86df3513
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/xml/X5_xmlPullTest.java
@@ -0,0 +1,95 @@
+package com.xdc.basic.api.xml;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import com.xdc.basic.skills.GetCurPath;
+
+public class X5_xmlPullTest
+{
+ public static void main(String[] args)
+ {
+ String curPath = GetCurPath.getCurPath();
+ try
+ {
+ XmlPullParserFactory pullParserFactory = XmlPullParserFactory.newInstance();
+ XmlPullParser xmlPullParser = pullParserFactory.newPullParser();
+
+ File file = new File(curPath + "students.xml");
+ Reader reader = new FileReader(file);
+ xmlPullParser.setInput(reader);
+
+ Student student = null;
+ int eventType = xmlPullParser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT)
+ {
+ String nodeName = xmlPullParser.getName();
+ switch (eventType)
+ {
+ case XmlPullParser.START_DOCUMENT:
+ break;
+
+ case XmlPullParser.START_TAG:
+ if ("student".equals(nodeName))
+ {
+ student = new Student();
+ student.setId(xmlPullParser.getAttributeValue(0));
+ }
+ else if ("name".equals(nodeName))
+ {
+ student.setName(xmlPullParser.nextText());
+ }
+ else if ("age".equals(nodeName))
+ {
+ student.setAge(xmlPullParser.nextText());
+ }
+ else if ("sex".equals(nodeName))
+ {
+ student.setSex(xmlPullParser.nextText());
+ }
+
+ else if ("address".equals(nodeName))
+ {
+ student.setAddress(xmlPullParser.nextText());
+ }
+ break;
+
+ case XmlPullParser.TEXT:
+ break;
+
+ case XmlPullParser.END_TAG:
+ if ("student".equals(nodeName))
+ {
+ System.out.println(student);
+ student = null;
+ }
+ break;
+
+ default:
+ break;
+ }
+ xmlPullParser.next();
+ eventType = xmlPullParser.getEventType();
+ }
+ }
+ catch (XmlPullParserException e)
+ {
+ e.printStackTrace();
+ }
+ catch (FileNotFoundException e)
+ {
+ e.printStackTrace();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/jdom2.format/src/com/xdc/PrettyPrinter.java b/basicKnowledge/src/com/xdc/basic/api/xml/formater/PrettyPrinter.java
similarity index 75%
rename from jdom2.format/src/com/xdc/PrettyPrinter.java
rename to basicKnowledge/src/com/xdc/basic/api/xml/formater/PrettyPrinter.java
index 574196f7..667b1724 100644
--- a/jdom2.format/src/com/xdc/PrettyPrinter.java
+++ b/basicKnowledge/src/com/xdc/basic/api/xml/formater/PrettyPrinter.java
@@ -1,4 +1,4 @@
-package com.xdc;
+package com.xdc.basic.api.xml.formater;
import java.io.File;
@@ -7,17 +7,20 @@
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
+import com.xdc.basic.skills.GetCurPath;
+
public class PrettyPrinter
{
public static void main(String[] args)
{
- String filename = "users.xml";
+ String curPath = GetCurPath.getCurPath();
+
try
{
// Build the document with SAX and Xerces, no validation
SAXBuilder builder = new SAXBuilder();
// Create the document
- Document doc = builder.build(new File(filename));
+ Document doc = builder.build(new File(curPath + "users.xml"));
// Output the document, use standard formatter
XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
outputter.output(doc, System.out);
diff --git a/basicKnowledge/src/com/xdc/basic/api/xml/formater/users.xml b/basicKnowledge/src/com/xdc/basic/api/xml/formater/users.xml
new file mode 100644
index 00000000..af30b881
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/xml/formater/users.xml
@@ -0,0 +1,14 @@
+
+
+ 小李
+ 男 24
+
+ 小丽
+ 女
+ 18
+
+ 小王
+ 男
+ 22
+
+
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/api/xml/students.xml b/basicKnowledge/src/com/xdc/basic/api/xml/students.xml
new file mode 100644
index 00000000..8630ec37
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/api/xml/students.xml
@@ -0,0 +1,63 @@
+
+
+
+ student0
+ 10
+ 女
+ 陕西西安
+
+
+ student1
+ 11
+ 男
+ 陕西西安
+
+
+ student2
+ 12
+ 女
+ 陕西西安
+
+
+ student3
+ 13
+ 男
+ 陕西西安
+
+
+ student4
+ 14
+ 女
+ 陕西西安
+
+
+ student5
+ 15
+ 男
+ 陕西西安
+
+
+ student6
+ 16
+ 女
+ 陕西西安
+
+
+ student7
+ 17
+ 男
+ 陕西西安
+
+
+ student8
+ 18
+ 女
+ 陕西西安
+
+
+ student9
+ 19
+ 男
+ 陕西西安
+
+
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/NameObserver.java b/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/NameObserver.java
new file mode 100644
index 00000000..c0fe999e
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/NameObserver.java
@@ -0,0 +1,21 @@
+package com.xdc.basic.book.designpattern.observer;
+
+import java.util.Observable;
+import java.util.Observer;
+
+// 观察者NameObserver主要用来对产品名称(name)进行观察的
+public class NameObserver implements Observer
+{
+ private String name = null;
+
+ @Override
+ public void update(Observable obj, Object arg)
+ {
+ if (arg instanceof String)
+ {
+ name = (String) arg;
+ // 产品名称改变值在name中
+ System.out.println("NameObserver: name changet to " + name);
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/ObserverTest.java b/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/ObserverTest.java
new file mode 100644
index 00000000..1c5f8a2d
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/ObserverTest.java
@@ -0,0 +1,19 @@
+package com.xdc.basic.book.designpattern.observer;
+
+public class ObserverTest
+{
+ public static void main(String[] args)
+ {
+ Product product = new Product();
+
+ NameObserver nameobs = new NameObserver();
+ PriceObserver priceobs = new PriceObserver();
+
+ // 加入观察者
+ product.addObserver(nameobs);
+ product.addObserver(priceobs);
+
+ product.setName("橘子红了");
+ product.setPrice(9.22f);
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/PriceObserver.java b/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/PriceObserver.java
new file mode 100644
index 00000000..ef4c0a3e
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/PriceObserver.java
@@ -0,0 +1,20 @@
+package com.xdc.basic.book.designpattern.observer;
+
+import java.util.Observable;
+import java.util.Observer;
+
+// 观察者PriceObserver主要用来对产品价格(price)进行观察的
+public class PriceObserver implements Observer
+{
+ private float price = 0;
+
+ public void update(Observable obj, Object arg)
+ {
+ if (arg instanceof Float)
+ {
+ price = ((Float) arg).floatValue();
+ // 产品价格改变值在price中
+ System.out.println("PriceObserver: price changet to " + price);
+ }
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/Product.java b/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/Product.java
new file mode 100644
index 00000000..79520df3
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/designpattern/observer/Product.java
@@ -0,0 +1,37 @@
+package com.xdc.basic.book.designpattern.observer;
+
+import java.util.Observable;
+
+// 产品类 可供Jsp直接使用UseBean调用 该类主要执行产品数据库插入 更新
+public class Product extends Observable
+{
+ private String name;
+ private float price;
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ // 设置变化点
+ setChanged();
+ // 变更会通过循环通知给所有观察者,观察者通过判断类型过滤掉他不关心的变更
+ notifyObservers(name);
+ }
+
+ public float getPrice()
+ {
+ return price;
+ }
+
+ public void setPrice(float price)
+ {
+ this.price = price;
+ // 设置变化点
+ setChanged();
+ notifyObservers(new Float(price));
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter10/Item66/brokenstopthread/StopThread.java b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter10/Item66/brokenstopthread/StopThread.java
new file mode 100644
index 00000000..bcce232b
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter10/Item66/brokenstopthread/StopThread.java
@@ -0,0 +1,28 @@
+package com.xdc.basic.book.effectivejava.Chapter10.Item66.brokenstopthread;
+
+// Broken! - How long would you expect this program to run? - Page 259
+
+import java.util.concurrent.TimeUnit;
+
+public class StopThread
+{
+ private static boolean stopRequested;
+
+ public static void main(String[] args) throws InterruptedException
+ {
+ Thread backgroundThread = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ @SuppressWarnings("unused")
+ int i = 0;
+ while (!stopRequested)
+ i++;
+ }
+ });
+ backgroundThread.start();
+
+ TimeUnit.SECONDS.sleep(1);
+ stopRequested = true;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter10/Item66/fixedstopthread1/StopThread.java b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter10/Item66/fixedstopthread1/StopThread.java
new file mode 100644
index 00000000..eb9c9619
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter10/Item66/fixedstopthread1/StopThread.java
@@ -0,0 +1,38 @@
+package com.xdc.basic.book.effectivejava.Chapter10.Item66.fixedstopthread1;
+
+// Properly synchronized cooperative thread termination - Page 261
+
+import java.util.concurrent.TimeUnit;
+
+public class StopThread
+{
+ private static boolean stopRequested;
+
+ private static synchronized void requestStop()
+ {
+ stopRequested = true;
+ }
+
+ private static synchronized boolean stopRequested()
+ {
+ return stopRequested;
+ }
+
+ public static void main(String[] args) throws InterruptedException
+ {
+ Thread backgroundThread = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ @SuppressWarnings("unused")
+ int i = 0;
+ while (!stopRequested())
+ i++;
+ }
+ });
+ backgroundThread.start();
+
+ TimeUnit.SECONDS.sleep(1);
+ requestStop();
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter10/Item66/fixedstopthread2/StopThread.java b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter10/Item66/fixedstopthread2/StopThread.java
new file mode 100644
index 00000000..8cc5717e
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter10/Item66/fixedstopthread2/StopThread.java
@@ -0,0 +1,28 @@
+package com.xdc.basic.book.effectivejava.Chapter10.Item66.fixedstopthread2;
+
+// Cooperative thread termination with a volatile field
+
+import java.util.concurrent.TimeUnit;
+
+public class StopThread
+{
+ private static volatile boolean stopRequested;
+
+ public static void main(String[] args) throws InterruptedException
+ {
+ Thread backgroundThread = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ @SuppressWarnings("unused")
+ int i = 0;
+ while (!stopRequested)
+ i++;
+ }
+ });
+ backgroundThread.start();
+
+ TimeUnit.SECONDS.sleep(1);
+ stopRequested = true;
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter2/Item2/builder/NutritionFacts.java b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter2/Item2/builder/NutritionFacts.java
new file mode 100644
index 00000000..425f01ed
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter2/Item2/builder/NutritionFacts.java
@@ -0,0 +1,77 @@
+package com.xdc.basic.book.effectivejava.Chapter2.Item2.builder;
+
+// Builder Pattern - Pages 14-15
+
+@SuppressWarnings("unused")
+public class NutritionFacts
+{
+ private final int servingSize;
+ private final int servings;
+ private final int calories;
+ private final int fat;
+ private final int sodium;
+ private final int carbohydrate;
+
+ public static class Builder
+ {
+ // Required parameters
+ private final int servingSize;
+ private final int servings;
+
+ // Optional parameters - initialized to default values
+ private int calories = 0;
+ private int fat = 0;
+ private int carbohydrate = 0;
+ private int sodium = 0;
+
+ public Builder(int servingSize, int servings)
+ {
+ this.servingSize = servingSize;
+ this.servings = servings;
+ }
+
+ public Builder calories(int val)
+ {
+ calories = val;
+ return this;
+ }
+
+ public Builder fat(int val)
+ {
+ fat = val;
+ return this;
+ }
+
+ public Builder carbohydrate(int val)
+ {
+ carbohydrate = val;
+ return this;
+ }
+
+ public Builder sodium(int val)
+ {
+ sodium = val;
+ return this;
+ }
+
+ public NutritionFacts build()
+ {
+ return new NutritionFacts(this);
+ }
+ }
+
+ private NutritionFacts(Builder builder)
+ {
+ servingSize = builder.servingSize;
+ servings = builder.servings;
+ calories = builder.calories;
+ fat = builder.fat;
+ sodium = builder.sodium;
+ carbohydrate = builder.carbohydrate;
+ }
+
+ public static void main(String[] args)
+ {
+ NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();
+ }
+}
\ No newline at end of file
diff --git a/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter3/Item12/PhoneNumber.java b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter3/Item12/PhoneNumber.java
new file mode 100644
index 00000000..da0e10de
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter3/Item12/PhoneNumber.java
@@ -0,0 +1,140 @@
+package com.xdc.basic.book.effectivejava.Chapter3.Item12;
+
+// Making PhoneNumber comparable - Pages 65-66
+
+import java.util.NavigableSet;
+import java.util.Random;
+import java.util.TreeSet;
+
+public final class PhoneNumber implements Cloneable, Comparable
+{
+ private final short areaCode;
+ private final short prefix;
+ private final short lineNumber;
+
+ public PhoneNumber(int areaCode, int prefix, int lineNumber)
+ {
+ rangeCheck(areaCode, 999, "area code");
+ rangeCheck(prefix, 999, "prefix");
+ rangeCheck(lineNumber, 9999, "line number");
+ this.areaCode = (short) areaCode;
+ this.prefix = (short) prefix;
+ this.lineNumber = (short) lineNumber;
+ }
+
+ private static void rangeCheck(int arg, int max, String name)
+ {
+ if (arg < 0 || arg > max)
+ throw new IllegalArgumentException(name + ": " + arg);
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ return true;
+ if (!(o instanceof PhoneNumber))
+ return false;
+ PhoneNumber pn = (PhoneNumber) o;
+ return pn.lineNumber == lineNumber && pn.prefix == prefix && pn.areaCode == areaCode;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = 17;
+ result = 31 * result + areaCode;
+ result = 31 * result + prefix;
+ result = 31 * result + lineNumber;
+ return result;
+ }
+
+ /**
+ * Returns the string representation of this phone number.
+ * The string consists of fourteen characters whose format
+ * is "(XXX) YYY-ZZZZ", where XXX is the area code, YYY is
+ * the prefix, and ZZZZ is the line number. (Each of the
+ * capital letters represents a single decimal digit.)
+ *
+ * If any of the three parts of this phone number is too small
+ * to fill up its field, the field is padded with leading zeros.
+ * For example, if the value of the line number is 123, the last
+ * four characters of the string representation will be "0123".
+ *
+ * Note that there is a single space separating the closing
+ * parenthesis after the area code from the first digit of the
+ * prefix.
+ */
+ @Override
+ public String toString()
+ {
+ return String.format("(%03d) %03d-%04d", areaCode, prefix, lineNumber);
+ }
+
+ @Override
+ public PhoneNumber clone()
+ {
+ try
+ {
+ return (PhoneNumber) super.clone();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new AssertionError(); // Can't happen
+ }
+ }
+
+ // Works fine, but can be made faster
+ // public int compareTo(PhoneNumber pn) {
+ // // Compare area codes
+ // if (areaCode < pn.areaCode)
+ // return -1;
+ // if (areaCode > pn.areaCode)
+ // return 1;
+ //
+ // // Area codes are equal, compare prefixes
+ // if (prefix < pn.prefix)
+ // return -1;
+ // if (prefix > pn.prefix)
+ // return 1;
+ //
+ // // Area codes and prefixes are equal, compare line numbers
+ // if (lineNumber < pn.lineNumber)
+ // return -1;
+ // if (lineNumber > pn.lineNumber)
+ // return 1;
+ //
+ // return 0; // All fields are equal
+ // }
+
+ public int compareTo(PhoneNumber pn)
+ {
+ // Compare area codes
+ int areaCodeDiff = areaCode - pn.areaCode;
+ if (areaCodeDiff != 0)
+ return areaCodeDiff;
+
+ // Area codes are equal, compare prefixes
+ int prefixDiff = prefix - pn.prefix;
+ if (prefixDiff != 0)
+ return prefixDiff;
+
+ // Area codes and prefixes are equal, compare line numbers
+ return lineNumber - pn.lineNumber;
+ }
+
+ public static void main(String[] args)
+ {
+ NavigableSet s = new TreeSet();
+ for (int i = 0; i < 10; i++)
+ s.add(randomPhoneNumber());
+ System.out.println(s);
+ }
+
+ private static final Random rnd = new Random();
+
+ private static PhoneNumber randomPhoneNumber()
+ {
+ return new PhoneNumber((short) rnd.nextInt(1000), (short) rnd.nextInt(1000), (short) rnd.nextInt(10000));
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/Operation.java b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/Operation.java
new file mode 100644
index 00000000..35a2a13b
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/Operation.java
@@ -0,0 +1,47 @@
+package com.xdc.basic.book.effectivejava.Chapter6.Item30;
+
+// Enum type with constant-specific class bodies and data - Page 153
+
+import java.util.*;
+
+public enum Operation {
+ PLUS("+") {
+ double apply(double x, double y) { return x + y; }
+ },
+ MINUS("-") {
+ double apply(double x, double y) { return x - y; }
+ },
+ TIMES("*") {
+ double apply(double x, double y) { return x * y; }
+ },
+ DIVIDE("/") {
+ double apply(double x, double y) { return x / y; }
+ };
+ private final String symbol;
+ Operation(String symbol) { this.symbol = symbol; }
+ @Override public String toString() { return symbol; }
+
+ abstract double apply(double x, double y);
+
+ // Implementing a fromString method on an enum type - Page 154
+ private static final Map stringToEnum
+ = new HashMap();
+ static { // Initialize map from constant name to enum constant
+ for (Operation op : values())
+ stringToEnum.put(op.toString(), op);
+ }
+ // Returns Operation for string, or null if string is invalid
+ public static Operation fromString(String symbol) {
+ return stringToEnum.get(symbol);
+ }
+
+
+ // Test program to perform all operations on given operands
+ public static void main(String[] args) {
+ double x = Double.parseDouble(args[0]);
+ double y = Double.parseDouble(args[1]);
+ for (Operation op : Operation.values())
+ System.out.printf("%f %s %f = %f%n",
+ x, op, y, op.apply(x, y));
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/PayrollDay.java b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/PayrollDay.java
new file mode 100644
index 00000000..7efd271d
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/PayrollDay.java
@@ -0,0 +1,38 @@
+package com.xdc.basic.book.effectivejava.Chapter6.Item30;
+
+// The strategy enum pattern
+enum PayrollDay {
+ MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY),
+ WEDNESDAY(PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY),
+ FRIDAY(PayType.WEEKDAY),
+ SATURDAY(PayType.WEEKEND), SUNDAY(PayType.WEEKEND);
+
+ private final PayType payType;
+ PayrollDay(PayType payType) { this.payType = payType; }
+
+ double pay(double hoursWorked, double payRate) {
+ return payType.pay(hoursWorked, payRate);
+ }
+ // The strategy enum type
+ private enum PayType {
+ WEEKDAY {
+ double overtimePay(double hours, double payRate) {
+ return hours <= HOURS_PER_SHIFT ? 0 :
+ (hours - HOURS_PER_SHIFT) * payRate / 2;
+ }
+ },
+ WEEKEND {
+ double overtimePay(double hours, double payRate) {
+ return hours * payRate / 2;
+ }
+ };
+ private static final int HOURS_PER_SHIFT = 8;
+
+ abstract double overtimePay(double hrs, double payRate);
+
+ double pay(double hoursWorked, double payRate) {
+ double basePay = hoursWorked * payRate;
+ return basePay + overtimePay(hoursWorked, payRate);
+ }
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/Planet.java b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/Planet.java
new file mode 100644
index 00000000..b782a590
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/Planet.java
@@ -0,0 +1,34 @@
+package com.xdc.basic.book.effectivejava.Chapter6.Item30;
+
+// Enum type with data and behavior - Pages 149-150
+public enum Planet {
+ MERCURY(3.302e+23, 2.439e6),
+ VENUS (4.869e+24, 6.052e6),
+ EARTH (5.975e+24, 6.378e6),
+ MARS (6.419e+23, 3.393e6),
+ JUPITER(1.899e+27, 7.149e7),
+ SATURN (5.685e+26, 6.027e7),
+ URANUS (8.683e+25, 2.556e7),
+ NEPTUNE(1.024e+26, 2.477e7);
+ private final double mass; // In kilograms
+ private final double radius; // In meters
+ private final double surfaceGravity; // In m / s^2
+
+ // Universal gravitational constant in m^3 / kg s^2
+ private static final double G = 6.67300E-11;
+
+ // Constructor
+ Planet(double mass, double radius) {
+ this.mass = mass;
+ this.radius = radius;
+ surfaceGravity = G * mass / (radius * radius);
+ }
+
+ public double mass() { return mass; }
+ public double radius() { return radius; }
+ public double surfaceGravity() { return surfaceGravity; }
+
+ public double surfaceWeight(double mass) {
+ return mass * surfaceGravity; // F = ma
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/WeightTable.java b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/WeightTable.java
new file mode 100644
index 00000000..c18fe366
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item30/WeightTable.java
@@ -0,0 +1,13 @@
+package com.xdc.basic.book.effectivejava.Chapter6.Item30;
+
+// Takes earth-weight and prints table of weights on all planets - Page 150
+
+public class WeightTable {
+ public static void main(String[] args) {
+ double earthWeight = Double.parseDouble(args[0]);
+ double mass = earthWeight / Planet.EARTH.surfaceGravity();
+ for (Planet p : Planet.values())
+ System.out.printf("Weight on %s is %f%n",
+ p, p.surfaceWeight(mass));
+ }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item31/Ensemble.java b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item31/Ensemble.java
new file mode 100644
index 00000000..e710df22
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item31/Ensemble.java
@@ -0,0 +1,12 @@
+package com.xdc.basic.book.effectivejava.Chapter6.Item31;
+
+// Enum with integer data stored in an instance field
+public enum Ensemble {
+ SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5),
+ SEXTET(6), SEPTET(7), OCTET(8), DOUBLE_QUARTET(8),
+ NONET(9), DECTET(10), TRIPLE_QUARTET(12);
+
+ private final int numberOfMusicians;
+ Ensemble(int size) { this.numberOfMusicians = size; }
+ public int numberOfMusicians() { return numberOfMusicians; }
+}
diff --git a/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item32/Text.java b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item32/Text.java
new file mode 100644
index 00000000..90ebdd97
--- /dev/null
+++ b/basicKnowledge/src/com/xdc/basic/book/effectivejava/Chapter6/Item32/Text.java
@@ -0,0 +1,20 @@
+package com.xdc.basic.book.effectivejava.Chapter6.Item32;
+
+// EnumSet - a modern replacement for bit fields - Page 160
+
+import java.util.*;
+
+public class Text {
+ public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }
+
+ // Any Set could be passed in, but EnumSet is clearly best
+ public void applyStyles(Set
+
+
+
+
+ ">Contact List
+
+
+
+
+
+
+
+
+
+
+
+
+
+<%
+ if(request.getUserPrincipal() != null) {
+%>
+
+
+
+
+
+
+
+<%
+ }
+%>
+
+
+
+ ,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/defError.jsp b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/defError.jsp
new file mode 100644
index 00000000..ef1490eb
--- /dev/null
+++ b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/defError.jsp
@@ -0,0 +1 @@
+DEFAULT ERROR
\ No newline at end of file
diff --git a/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/edit.jsp b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/edit.jsp
new file mode 100644
index 00000000..8a2e7441
--- /dev/null
+++ b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/edit.jsp
@@ -0,0 +1,20 @@
+<%@ taglib prefix="portlet" uri="http://java.sun.com/portlet" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
+
+Rolodex settings
+
+
diff --git a/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/editContact.jsp b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/editContact.jsp
new file mode 100644
index 00000000..aba23239
--- /dev/null
+++ b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/editContact.jsp
@@ -0,0 +1,53 @@
+<%@ taglib prefix="portlet"
+ uri="http://java.sun.com/portlet" %>
+<%@ taglib prefix="spring"
+ uri="http://www.springframework.org/tags" %>
+<%@ taglib prefix="form"
+ uri="http://www.springframework.org/tags/form" %>
+Contact Edit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/help.jsp b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/help.jsp
new file mode 100644
index 00000000..635a1bbd
--- /dev/null
+++ b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/help.jsp
@@ -0,0 +1,7 @@
+Rolodex Help
+
+Copyright © 2006 Craig Walls
+
+This is the example porlet application used in my "Thinking inside
+the box" presentation. It demonstrates the use of Spring's Portlet MVC
+framework.
diff --git a/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/notAuthorized.jsp b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/notAuthorized.jsp
new file mode 100644
index 00000000..11e6da84
--- /dev/null
+++ b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/notAuthorized.jsp
@@ -0,0 +1 @@
+NOT AUTHORIZED
\ No newline at end of file
diff --git a/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/notAvailable.jsp b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/notAvailable.jsp
new file mode 100644
index 00000000..cb7c066b
--- /dev/null
+++ b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/jsp/notAvailable.jsp
@@ -0,0 +1 @@
+NOT AVAILABLE
diff --git a/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/portlet.xml b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/portlet.xml
new file mode 100644
index 00000000..ded58fb0
--- /dev/null
+++ b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/portlet.xml
@@ -0,0 +1,49 @@
+
+
+
+ Hello
+
+ com.springinaction.hello.HelloPortlet
+
+
+ text/html
+ view
+
+
+ Hello World
+ Hello World
+ Hello,World
+
+
+
+
+ Rolodex
+
+ org.springframework.web.portlet.DispatcherPortlet
+
+
+ text/html
+ view
+ edit
+ help
+
+
+ My Contacts
+ My Contacts
+ Contacts,Rolodex
+
+
+
+ pageSize
+ 5
+
+
+
+
+
diff --git a/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/web.xml b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..71598752
--- /dev/null
+++ b/springInAction/Portlet/Rolodex/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,78 @@
+
+
+
+
+ Rolodex
+
+
+ log4jConfigLocation
+ /WEB-INF/classes/log4j.properties
+
+
+
+ contextConfigLocation
+
+ /WEB-INF/Rolodex-service.xml
+ /WEB-INF/Rolodex-data.xml
+
+
+
+
+ org.springframework.web.context.ContextLoaderListener
+
+
+
+
+ ViewRendererServlet
+
+ org.springframework.web.servlet.ViewRendererServlet
+ 1
+
+
+
+ Rolodex
+ org.apache.pluto.core.PortletServlet
+
+ portlet-name
+ Rolodex
+
+ 1
+
+
+
+ ViewRendererServlet
+ /WEB-INF/servlet/view
+
+
+
+ Rolodex
+ /PlutoInvoker/Rolodex
+
+
+
+
diff --git a/springInAction/Portlet/Rolodex/src/main/webapp/images/edit.gif b/springInAction/Portlet/Rolodex/src/main/webapp/images/edit.gif
new file mode 100644
index 00000000..0e79cff0
Binary files /dev/null and b/springInAction/Portlet/Rolodex/src/main/webapp/images/edit.gif differ
diff --git a/springInAction/Portlet/Rolodex/src/main/webapp/images/trash.gif b/springInAction/Portlet/Rolodex/src/main/webapp/images/trash.gif
new file mode 100644
index 00000000..802f0900
Binary files /dev/null and b/springInAction/Portlet/Rolodex/src/main/webapp/images/trash.gif differ
diff --git a/springInAction/Portlet/Rolodex/src/main/webapp/images/view.gif b/springInAction/Portlet/Rolodex/src/main/webapp/images/view.gif
new file mode 100644
index 00000000..a6a08153
Binary files /dev/null and b/springInAction/Portlet/Rolodex/src/main/webapp/images/view.gif differ
diff --git a/springInAction/Portlet/Rolodex/src/test/java/com/springinaction/rolodex/controller/ContactsControllerTest.java b/springInAction/Portlet/Rolodex/src/test/java/com/springinaction/rolodex/controller/ContactsControllerTest.java
new file mode 100644
index 00000000..0de43359
--- /dev/null
+++ b/springInAction/Portlet/Rolodex/src/test/java/com/springinaction/rolodex/controller/ContactsControllerTest.java
@@ -0,0 +1,66 @@
+package com.springinaction.rolodex.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.easymock.MockControl;
+import org.springframework.mock.web.portlet.MockRenderRequest;
+import org.springframework.mock.web.portlet.MockRenderResponse;
+import org.springframework.web.portlet.ModelAndView;
+
+import com.springinaction.rolodex.controller.ContactsController;
+import com.springinaction.rolodex.domain.Contact;
+import com.springinaction.rolodex.service.RolodexService;
+
+
+public class ContactsControllerTest extends TestCase {
+ public ContactsControllerTest() {
+ super();
+ }
+
+ public ContactsControllerTest(String name) {
+ super(name);
+ }
+
+ private ContactsController controller;
+
+ private MockControl control;
+ private RolodexService rolodexService;
+
+ protected void setUp() throws Exception {
+
+ control = MockControl.createControl(RolodexService.class);
+ rolodexService = (RolodexService) control.getMock();
+ rolodexService.getContacts(null);
+ List contactList = new ArrayList();
+ Contact contact = new Contact();
+ contactList.add(contact);
+ control.expectAndReturn(null, contactList);
+ control.replay();
+
+ controller = new ContactsController();
+ controller.setRolodexService(rolodexService);
+ }
+
+ public void testNoAuthRequest() {
+ MockRenderRequest request = new MockRenderRequest();
+ MockRenderResponse response = new MockRenderResponse();
+
+ try {
+ ModelAndView mv = controller.handleRenderRequestInternal(request, response);
+
+ assertEquals("contactList", mv.getViewName());
+
+ Map model = mv.getModel();
+ assertNotNull(model);
+
+ List contacts = (List) model.get("contacts");
+ assertEquals(1, contacts.size());
+ } catch (Exception e) {
+ fail("Exception thrown from ContactsController.handleRenderRequestInternal() : " + e);
+ }
+ }
+}
diff --git a/springInAction/RoadRantz/.classpath b/springInAction/RoadRantz/.classpath
new file mode 100644
index 00000000..7adb0ee0
--- /dev/null
+++ b/springInAction/RoadRantz/.classpath
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/springInAction/RoadRantz/.project b/springInAction/RoadRantz/.project
new file mode 100644
index 00000000..ffdf58cf
--- /dev/null
+++ b/springInAction/RoadRantz/.project
@@ -0,0 +1,35 @@
+
+
+ RoadRantz
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.springframework.ide.eclipse.core.springbuilder
+
+
+
+
+ org.maven.ide.eclipse.maven2Builder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.m2e.core.maven2Nature
+ org.eclipse.jdt.core.javanature
+ org.maven.ide.eclipse.maven2Nature
+ org.springframework.ide.eclipse.core.springnature
+
+
diff --git a/springInAction/RoadRantz/.settings/org.eclipse.jdt.core.prefs b/springInAction/RoadRantz/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..abec6ca3
--- /dev/null
+++ b/springInAction/RoadRantz/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/springInAction/RoadRantz/.settings/org.eclipse.m2e.core.prefs b/springInAction/RoadRantz/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 00000000..f897a7f1
--- /dev/null
+++ b/springInAction/RoadRantz/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/springInAction/RoadRantz/.springBeans b/springInAction/RoadRantz/.springBeans
new file mode 100644
index 00000000..0e37a313
--- /dev/null
+++ b/springInAction/RoadRantz/.springBeans
@@ -0,0 +1,32 @@
+
+
+
+ xml
+
+
+ src/main/resources/roadrantz-data-jdbc.xml
+ src/main/resources/roadrantz-cache.xml
+ src/main/resources/roadrantz-jms.xml
+ src/main/resources/roadrantz-mbeans.xml
+ src/main/resources/roadrantz-data-hibernate.xml
+ src/main/resources/roadrantz-services.xml
+ src/main/resources/roadrantz-security.xml
+ src/main/resources/roadrantz-servlet.xml
+ src/main/resources/roadrantz-views.xml
+ src/main/resources/roadrantz-data-ibatis.xml
+ src/main/resources/roadrantz-data.xml
+ src/main/resources/roadrantz-data-jpa.xml
+
+
+
+ Servlet, service, and data
+ false
+ false
+
+ src/main/resources/roadrantz-data.xml
+ src/main/resources/roadrantz-services.xml
+ src/main/resources/roadrantz-servlet.xml
+
+
+
+
diff --git a/springInAction/RoadRantz/README b/springInAction/RoadRantz/README
new file mode 100644
index 00000000..26038380
--- /dev/null
+++ b/springInAction/RoadRantz/README
@@ -0,0 +1,171 @@
+WHAT THE HECK IS ROADRANTZ?
+===========================
+If you've been reading the book, you're probably wondering what RoadRantz is.
+Well, I had intended to write a short "About RoadRantz" segment to fit nicely
+in between chapters 4 and 5. Unfortunately, due to size and time constraints
+that never happened.
+
+In some attempt to make up for it, I'm going to attempt to settle the question
+of what RoadRantz is with this file.
+
+It started that day I almost died
+---------------------------------
+Like many people in today's workforce, I have spent a large portion of my
+life driving to and from work. The reality is that most of my jobs have been
+nowhere near my home and I've been required to commute up to an hour and a
+half each way (worst case).
+
+Whether you realize it or not, we share the road with a bunch of complete
+idiots. I generally don't have any bias against idiots--they can't help it
+that their brain capacity is low. But if you're an idiot, I really wish that
+you'd recognize your limitations and not try to do more than one thing while
+you're driving. And, in fact, I'd really prefer it if that one thing was to
+focus on driving your car.
+
+But apparently idiots (because they're idiots) don't take their limits
+into consideration and attempt to do all kinds of things while behind the
+wheel. I've seen things ranging from the basic cell-phone talker to the
+woman who emptied an entire can of hair spray while engaged in a hopeless
+attempt to beautify herself. In all cases, the motorists were putting
+themselves and others on the road in danger.
+
+In short, if you're busy doing anything other than driving, you're not
+going to be able to drive that well. Not to mention, that much hair spray
+creates a blinding haze that limits your visibility.
+
+Anyway, on one particular day, one of those idiots almost broad-sided me,
+swerving at the last second. I was certain that I had almost died--they were
+certain that they had just lost their cell signal.
+
+At that time, I decided there needed to be a way for me and other drivers to
+vent about those idiots on the road that fail to recognize that they're
+endangering others lives with their reckless commute-time habits.
+
+And so on that day, the idea of RoadRantz was born.
+
+Because I thought that the internet could use another community site
+--------------------------------------------------------------------
+RoadRantz is a community site in the same vein as MySpace or Facebook. The
+big difference is that instead of building a community of friends (Why do
+you need that? If they're you're friends you should just call them or go
+get pizza or something.) you're building a community of people you've
+encountered in traffic.
+
+The idea started simple enough: Take note of an idiot's license plate number
+and then go online to tell anyone and everyone how this particular motorist
+really needs to pull his head out of whatever orifice it has been placed in.
+If the driver in question is really that bad, they'll probably rack up a
+lengthy list of rants on RoadRantz.
+
+Then the idea grew a little. It's certainly fun to let off some steam by
+ranting about a fellow motorist. But RoadRantz could also be used for more
+friendly encounters. Let's say you just pulled up next to a rather toothsome
+driver at a red light. It could also be fun to leave a message for him/her
+to let them know that they caught your eye.
+
+The opportunities to hook-up on RoadRantz are endless. Whether you're angry
+with a fellow road-hog or simply want to arrange another traffic-light
+encounter, RoadRantz can be a lot of fun.
+
+What's in this project
+----------------------
+I decided that RoadRantz would be a fun example for Spring in Action, 2E.
+That's because it covers so much of the ground that would also be covered
+in the book. No example is perfect and I couldn't easily use RoadRantz for
+all sections in the book. But I think it does a good job of demonstrating
+most of the topics in SiA2.
+
+What you'll find in this project is a large portion of the RoadRantz
+application. But not all of the application is here. That's because I've
+had to focus my energy on getting the book done. Therefore, I've built just
+enough of the RoadRantz application to demonstrate the concepts in the book
+and only a little more than that.
+
+The problem with trying to demonstrate a wealth of Spring techniques in
+a simple application is that you end up with a hammer in search of nails.
+That is, I needed to demonstrate something, so in some cases I shoe-horned
+an example into the RoadRantz application, even if I probably wouldn't
+actually use that example in the real RoadRantz application.
+
+Now that the book is done, I intend to continue working on the RoadRantz
+application as a toy project. That means that I'll continue to add
+functionality and will continue to evolve the design. I'll also clean up
+the application, removing some of the examples that don't quite fit.
+And eventually I'll deploy it for public consumption.
+
+If you want to follow along with the changes I make, you can check out the
+code from svn://svn.geekisp.com/SiA. The new changes will be made on the
+trunk, but you can always retrieve the original book version of the code
+from the BOOK-1.0 tag.
+
+The basic design of RaodRantz
+-----------------------------
+Lately, I've become captivated by the idea of Domain Driven Design, as
+presented at length in Erik Evans' "Domain Driven Design: Tackling Complexity
+in the Heart of Software" and other related books and writings.
+
+Unfortunately, that interest in DDD came too late to impact the design of
+the RoadRantz application.
+
+So, RoadRantz follows a fairly basic layered approach consisting of a
+presentation layer, a business layer, and a persistence layer. Transcending
+all of those layers is a handful of domain objects, although not exactly
+the same rich domain-layer you might find discussed in Eric Evans' book.
+
+In the presentation layer you'll find things like Spring MVC and, to a
+lesser extent, Struts, WebWork, Tapestry, and JSF.
+
+The business layer consists of the RantService interface and its
+implementation. The primary role Spring plays in this layer is to provide
+declarative transactions for the service methods. But there are also other
+service-related items such as e-mail support that show up here.
+
+The persistence layer is where you'll find Spring simplifying JDBC, JPA,
+Hibernate, and iBATIS to access the database. You'll also find the Spring
+Modules' cache implementation playing a part in improving the performance
+for frequently performed queries.
+
+I've come to believe that no matter how much work I put into a design, I'll
+always have regrets and end up wishing I had another chance to do it better.
+But the 2nd edition is printed and there's little I can do to change that
+now. If I do a 3rd edition of Spring in Action, then I suppose I can correct
+the design of RoadRantz to fit the DDD approach. Until then, you can follow
+along as I rework RoadRantz by checking out the latest code from the trunk
+of the Subversion repository (see above).
+
+Building RoadRantz
+------------------
+I'm using Maven 2 to build the RoadRantz application. Everything you need
+should already be in the pom.xml file, so you'll only need to type this
+to build a WAR file:
+
+ % mvn package
+
+When it's done, there'll be a RoadRantz.war file in the target directory.
+I don't anticipate any problems deploying this in any JEE web container,
+but I have only tried it in Tomcat (5.5.x and 6.0.x). If you run into any
+trouble getting it to run in any other container, let me know. Even better,
+since I may not have access to your container, any patch you can submit to
+fix it to work in your container would be welcome.
+
+Another thing: You'll need a database. In the db directory, you'll find
+a create-tables.sql file which includes SQL for creating the tables in
+Hypersonic. You'll need to tweak those in order to use a different database.
+
+The RantService tests (RantServiceTest*.java) are excluded from normal
+test execution in the Maven pom.xml file. That's because they're not
+really unit-tests and because they require a database to be setup and
+running in order to test the RantService implementation. If you want to
+run those tests, you'll need to specify the "itest" Maven profile, as
+follows:
+
+ % mvc -P itest test
+
+At the moment, you'll need a running database to run those integration
+tests against RantServiceImpl. I intend to eventually rework those tests to
+use an in-memory Hypersonic database so they won't need a database otherwise.
+But for now, be sure to have a DB going.
+
+One final detail: Once you've got the database setup, you'll want to tweak
+the database connection properties. Those are setup in the db.properties file.
+
diff --git a/springInAction/RoadRantz/build.xml b/springInAction/RoadRantz/build.xml
new file mode 100644
index 00000000..92918789
--- /dev/null
+++ b/springInAction/RoadRantz/build.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/springInAction/RoadRantz/db/create-tables.sql b/springInAction/RoadRantz/db/create-tables.sql
new file mode 100644
index 00000000..4cf55827
--- /dev/null
+++ b/springInAction/RoadRantz/db/create-tables.sql
@@ -0,0 +1,35 @@
+drop table Rant if exists
+drop table Vehicle if exists
+drop table Motorist_Privileges if exists
+drop table Motorist if exists
+
+create table Rant (
+ id integer identity primary key,
+ vehicle_id integer not null,
+ rantText varchar(2000) not null,
+ postedDate date not null
+);
+
+create table Motorist (
+ id integer identity primary key,
+ email varchar(255) not null,
+ password varchar(50) not null,
+ firstName varchar(30) not null,
+ lastName varchar(30) not null
+);
+
+create table Vehicle (
+ id integer identity primary key,
+ motorist_id integer,
+ state varchar(2) not null,
+ plateNumber varchar(10) not null
+);
+
+create table Motorist_Privileges (
+ motorist_id integer not null,
+ privilege varchar(30) not null
+);
+
+alter table Vehicle add constraint vehicle_motorist foreign key (motorist_id) references Motorist;
+alter table Rant add constraint rant_vehicle foreign key (vehicle_id) references Vehicle;
+alter table Motorist_Privileges add constraint priv_motorist foreign key (motorist_id) references Motorist;
diff --git a/springInAction/RoadRantz/lib/ejb3-persistence.jar b/springInAction/RoadRantz/lib/ejb3-persistence.jar
new file mode 100644
index 00000000..1ec7f409
Binary files /dev/null and b/springInAction/RoadRantz/lib/ejb3-persistence.jar differ
diff --git a/springInAction/RoadRantz/lib/hsqldb.jar b/springInAction/RoadRantz/lib/hsqldb.jar
new file mode 100644
index 00000000..35436d6e
Binary files /dev/null and b/springInAction/RoadRantz/lib/hsqldb.jar differ
diff --git a/springInAction/RoadRantz/lib/incubator-activemq-4.0.1.jar b/springInAction/RoadRantz/lib/incubator-activemq-4.0.1.jar
new file mode 100644
index 00000000..10c79da5
Binary files /dev/null and b/springInAction/RoadRantz/lib/incubator-activemq-4.0.1.jar differ
diff --git a/springInAction/RoadRantz/license.txt b/springInAction/RoadRantz/license.txt
new file mode 100644
index 00000000..83f0ef5f
--- /dev/null
+++ b/springInAction/RoadRantz/license.txt
@@ -0,0 +1,5 @@
+
+This work is licensed under the Creative Commons Attribution 3.0 License. To view
+a copy of this license, visit http://creativecommons.org/licenses/by/3.0/ or send
+a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California,
+94105, USA.
diff --git a/springInAction/RoadRantz/pom.xml b/springInAction/RoadRantz/pom.xml
new file mode 100644
index 00000000..1cb9368b
--- /dev/null
+++ b/springInAction/RoadRantz/pom.xml
@@ -0,0 +1,454 @@
+
+
+
+ com.springinaction
+ sia
+ 2.0
+
+ 4.0.0
+ com.roadrantz
+ RoadRantz
+ war
+ Spring in Action 2E, RoadRantz Example
+ 1.0
+ http://www.habuma.com
+
+
+
+ java.net
+ https://maven-repository.dev.java.net/nonav/repository
+ legacy
+
+
+
+
+ RoadRantz
+
+
+
+ org.codehaus.cargo
+ cargo-maven2-plugin
+
+
+ tomcat5x
+ remote
+
+
+ runtime
+
+ localhost
+ 8080
+ admin2
+ password
+
+
+
+
+
+
+
+ maven-surefire-plugin
+
+
+ **/*RantServiceTest*.java
+
+
+
+
+
+ maven-compiler-plugin
+
+ 1.5
+ 1.5
+
+
+
+
+
+
+
+
+
+
+ tomcat5x
+
+ true
+
+
+ tomcat5x
+
+
+
+
+
+ itest
+
+
+ itest
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ surefire-it
+ integration-test
+
+ test
+
+
+
+ none
+
+
+ **/*RantServiceTest*.java
+
+
+
+
+
+
+
+
+
+
+
+ 0.8a
+
+
+
+
+ org.springframework
+ spring-mock
+ ${spring.version}
+ test
+
+
+ org.springmodules
+ spring-modules-validation
+ ${spring.modules.version}
+ compile
+
+
+ org.springmodules
+ spring-modules-cache
+ ${spring.modules.version}
+ compile
+
+
+
+
+ gigaspaces
+ gigaspaces-ce
+
+
+ jini
+ webster
+
+
+ jboss
+ jboss-jmx
+
+
+ xpp3
+ xpp3_min
+
+
+ jini
+ start
+
+
+ jboss
+ jboss-minimal
+
+
+ jini
+ reggie
+
+
+ jboss
+ jboss-cache
+
+
+ jcs
+ jcs
+
+
+ jboss
+ jboss-system
+
+
+ jini
+ jsk-platform
+
+
+ jboss
+ jboss-common
+
+
+ jini
+ mahalo
+
+
+ jini
+ jsk-lib
+
+
+ jini
+ boot
+
+
+
+
+ ehcache
+ ehcache
+
+
+
+
+ commons-attributes
+ commons-attributes-compiler
+
+
+
+
+ org.apache.geronimo.specs
+ geronimo-ejb_2.1_spec
+ 1.1
+ compile
+
+
+ commons-validator
+ commons-validator
+ 1.1.4
+ compile
+
+
+ commons-lang
+ commons-lang
+ 2.1
+ compile
+
+
+ commons-digester
+ commons-digester
+ 1.5
+ compile
+
+
+ hsqldb
+ hsqldb
+ 1.8.0.7
+ compile
+
+
+ org.hibernate
+ hibernate-annotations
+ 3.2.1.ga
+ compile
+
+
+ org.hibernate
+ hibernate
+ 3.2.1.ga
+ compile
+
+
+ com.ibatis
+ ibatis2-sqlmap
+ 2.1.7.597
+ compile
+
+
+ com.ibatis
+ ibatis2-common
+ 2.1.7.597
+ compile
+
+
+ javax.servlet
+ jstl
+ 1.1.2
+
+
+ taglibs
+ standard
+ 1.1.2
+
+
+
+ rome
+ rome
+ 0.8
+ compile
+
+
+ oro
+ oro
+ 2.0.8
+ compile
+
+
+ javax.servlet
+ servlet-api
+ 2.4
+ provided
+
+
+ velocity
+ velocity
+ 1.4
+ compile
+
+
+ freemarker
+ freemarker
+ 2.3.4
+ compile
+
+
+ struts
+ struts
+ 1.2.8
+ compile
+
+
+ poi
+ poi
+ 2.5.1-final-20040804
+ compile
+
+
+ com.lowagie
+ itext
+ 1.3.1
+ compile
+
+
+ org.easymock
+ easymock
+ 2.0
+ test
+
+
+ aspectj
+ aspectjrt
+ 1.5.0
+
+
+ aspectj
+ aspectjweaver
+ 1.5.0
+
+
+ org.acegisecurity
+ acegi-security
+ 1.0.3
+
+
+ org.springframework
+ spring-aop
+
+
+ org.springframework
+ spring-context
+
+
+ org.springframework
+ spring-dao
+
+
+ org.springframework
+ spring-remoting
+
+
+ org.springframework
+ spring-support
+
+
+ org.springframework
+ spring-jdbc
+
+
+ xerces
+ xercesImpl
+
+
+
+
+ opensymphony
+ quartz
+ 1.5.2
+ compile
+
+
+ commons-dbcp
+ commons-dbcp
+ 1.2.1
+ compile
+
+
+ xerces
+ xercesImpl
+
+
+
+
+ javax.mail
+ mail
+ 1.4
+ compile
+
+
+ opensymphony
+ webwork
+ 2.2.3
+ compile
+
+
+ tapestry
+ tapestry
+ 4.0.2
+ compile
+
+
+ tapestry
+ tapestry-annotations
+ 4.0.2
+ compile
+
+
+ org.apache.activemq
+ activemq-core
+ 4.1.1
+ compile
+
+
+ org.logicblaze.lingo
+ lingo
+ 1.2.1
+
+
+ toplink.essentials
+ toplink-essentials
+ 2.0-36
+ compile
+
+
+
\ No newline at end of file
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/DaoMain.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/DaoMain.java
new file mode 100644
index 00000000..945b3f92
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/DaoMain.java
@@ -0,0 +1,39 @@
+package com.roadrantz.dao;
+
+import java.util.Date;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.FileSystemXmlApplicationContext;
+
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+import com.roadrantz.service.RantService;
+
+public class DaoMain {
+ public static void main(String[] args) {
+ ApplicationContext ctx = new FileSystemXmlApplicationContext(new String[] {
+ "src/main/webapp/WEB-INF/services.xml", "src/main/webapp/WEB-INF/dataaccess.xml"
+ });
+
+ RantService dao = (RantService) ctx.getBean("rantService");
+
+ Rant rant = new Rant();
+ rant.setPostedDate(new Date());
+ rant.setRantText("TEST RANT 3");
+ Vehicle vehicle = new Vehicle();
+ vehicle.setPlateNumber("J55DNY");
+ vehicle.setState("TX");
+ rant.setVehicle(vehicle);
+ dao.addRant(rant);
+
+ rant = new Rant();
+ rant.setPostedDate(new Date());
+ rant.setRantText("TEST RANT 4");
+ vehicle = new Vehicle();
+ vehicle.setPlateNumber("G44MNX");
+ vehicle.setState("TX");
+ rant.setVehicle(vehicle);
+ dao.addRant(rant);
+
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/RantDao.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/RantDao.java
new file mode 100644
index 00000000..1456bbb5
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/RantDao.java
@@ -0,0 +1,30 @@
+package com.roadrantz.dao;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springmodules.cache.annotations.CacheFlush;
+import org.springmodules.cache.annotations.Cacheable;
+
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+public interface RantDao {
+ @CacheFlush(modelId="rantzCacheModel")
+ public void saveRant(Rant rant);
+
+ @Cacheable(modelId="rantzCacheModel")
+ public List getAllRants();
+
+ @Cacheable(modelId="rantzCacheModel")
+ public List getRantsForDay(Date day);
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber);
+ public void saveVehicle(Vehicle vehicle);
+
+ public Motorist getMotoristByEmail(String email);
+ public void saveMotorist(Motorist driver);
+
+ public int getMotoristCount();
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/UserDaoImpl.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/UserDaoImpl.java
new file mode 100644
index 00000000..64d650dc
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/UserDaoImpl.java
@@ -0,0 +1,48 @@
+package com.roadrantz.dao;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+import org.acegisecurity.GrantedAuthority;
+import org.acegisecurity.GrantedAuthorityImpl;
+import org.acegisecurity.userdetails.User;
+import org.acegisecurity.userdetails.UserDetails;
+import org.acegisecurity.userdetails.UserDetailsService;
+import org.acegisecurity.userdetails.UsernameNotFoundException;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.core.support.JdbcDaoSupport;
+
+public class UserDaoImpl extends JdbcDaoSupport
+ implements UserDetailsService {
+
+ public UserDaoImpl() {}
+
+ public UserDetails loadUserByUsername(String userName)
+ throws UsernameNotFoundException, DataAccessException {
+
+ List users = getJdbcTemplate().query(
+ "select email, password from driver where email=?",
+ new Object[] {userName},
+ new RowMapper() {
+ public Object mapRow(ResultSet rs, int rowNum)
+ throws SQLException {
+ String userName = rs.getString(1);
+ String password = rs.getString(2);
+
+ return new User(userName, password, true, true, true, true,
+ new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER")});
+ };
+ }
+ );
+
+ if(users.size() > 0) {
+ return (UserDetails) users.get(0);
+ }
+
+ throw new UsernameNotFoundException(userName);
+ }
+
+
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/hibernate/HibernateContextualSessionsRantDao.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/hibernate/HibernateContextualSessionsRantDao.java
new file mode 100644
index 00000000..b2bd0a0b
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/hibernate/HibernateContextualSessionsRantDao.java
@@ -0,0 +1,100 @@
+package com.roadrantz.dao.hibernate;
+
+import java.util.Date;
+import java.util.List;
+
+import org.hibernate.Hibernate;
+import org.hibernate.SessionFactory;
+import org.hibernate.type.Type;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+/**
+ * Hibernate contextual session based DAO.
+ *
+ * Although the name is different, this is the Hibernate-based DAO that is
+ * described in section 5.4.4.
+ *
+ * Note that since chapter 5 was written, I have learned that this is the
+ * preferred approach to building Hibernate DAOs.
+ *
+ * @author wallsc
+ */
+public class HibernateContextualSessionsRantDao implements RantDao {
+ private static final String MOTORIST = Motorist.class.getName();
+ private static final String RANT = Rant.class.getName();
+ private static final String VEHICLE = Vehicle.class.getName();
+
+ public HibernateContextualSessionsRantDao() {}
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+ List results = sessionFactory
+ .getCurrentSession()
+ .find(
+ "from "
+ + VEHICLE
+ + " where state = ? and plateNumber = ?",
+ new Object[] { state, plateNumber },
+ new Type[] { Hibernate.STRING,
+ Hibernate.STRING });
+
+ if (results.size() > 0) {
+ return (Vehicle) results.get(0);
+ }
+
+ return null; // TODO - Should I throw an exception instead?
+ }
+
+ public List getAllRants() {
+ return sessionFactory.getCurrentSession().find("from " + RANT);
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ List results = sessionFactory.getCurrentSession()
+ .find("from " + MOTORIST + " where email = ?",
+ new Object[] { email },
+ new Type[] { Hibernate.STRING });
+
+ if (results.size() > 0) {
+ return (Motorist) results.get(0);
+ }
+ return null; // TODO - Should I throw an exception instead?
+ }
+
+ public void saveRant(Rant rant) {
+ sessionFactory.getCurrentSession().saveOrUpdate(rant);
+ }
+
+ public void saveVehicle(Vehicle vehicle) {
+ sessionFactory.getCurrentSession().saveOrUpdate(vehicle);
+ }
+
+ public List getRantsForDay(Date day) {
+ return sessionFactory.getCurrentSession().find(
+ "from " + RANT + " where postedDate = ?", day,
+ Hibernate.DATE);
+ }
+
+ public void saveMotorist(Motorist driver) {
+ sessionFactory.getCurrentSession().saveOrUpdate(driver);
+ }
+
+ public Motorist getDriverById(Integer id) {
+ return (Motorist) sessionFactory.getCurrentSession().load(Motorist.class,
+ id);
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ private SessionFactory sessionFactory;
+
+ public void setSessionFactory(SessionFactory sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/hibernate/HibernateRantDao.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/hibernate/HibernateRantDao.java
new file mode 100644
index 00000000..6e99ae4b
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/hibernate/HibernateRantDao.java
@@ -0,0 +1,85 @@
+package com.roadrantz.dao.hibernate;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+/**
+ * Hibernate-based implementation of the RantDao interface.
+ *
+ * Initially defined in Listing 5.8. But the initial implementation of
+ * HibernateRantDao evolves in section 5.4.3 to extend HibernateDaoSupport.
+ *
+ * If you're looking for the version from section 5.4.2, have a look at
+ * HibernateRantDaoUsingTemplate.java.
+ *
+ * @author wallsc
+ */
+public class HibernateRantDao extends HibernateDaoSupport implements RantDao {
+ private static final String MOTORIST = Motorist.class.getName();
+ private static final String RANT = Rant.class.getName();
+ private static final String VEHICLE = Vehicle.class.getName();
+
+ public HibernateRantDao() {}
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+ List results = getHibernateTemplate()
+ .find(
+ "from "
+ + VEHICLE
+ + " where state = ? and plateNumber = ?",
+ new Object[] { state, plateNumber });
+
+ if (results.size() > 0) {
+ return (Vehicle) results.get(0);
+ }
+
+ return null; // TODO - Should I throw an exception instead?
+ }
+
+ public List getAllRants() {
+ return getHibernateTemplate().find("from " + RANT);
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ List results = getHibernateTemplate().find(
+ "from " + MOTORIST + " where email = ?", email);
+
+ if (results.size() > 0) {
+ return (Motorist) results.get(0);
+ }
+ return null; // TODO - Should I throw an exception instead?
+ }
+
+ public void saveRant(Rant rant) {
+ getHibernateTemplate().saveOrUpdate(rant);
+ }
+
+ public void saveVehicle(Vehicle vehicle) {
+ getHibernateTemplate().saveOrUpdate(vehicle);
+ }
+
+ public List getRantsForDay(Date day) {
+ return getHibernateTemplate().find(
+ "from " + RANT + " where postedDate = ?", day);
+ }
+
+ public void saveMotorist(Motorist driver) {
+ getHibernateTemplate().saveOrUpdate(driver);
+ }
+
+ public Motorist getDriverById(Integer id) {
+ return (Motorist) getHibernateTemplate().load(Motorist.class, id);
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/hibernate/HibernateRantDaoUsingTemplate.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/hibernate/HibernateRantDaoUsingTemplate.java
new file mode 100644
index 00000000..7873c908
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/hibernate/HibernateRantDaoUsingTemplate.java
@@ -0,0 +1,90 @@
+package com.roadrantz.dao.hibernate;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.orm.hibernate3.HibernateTemplate;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+/**
+ * This class is an alternate implementation of HibernateRantDao, that more
+ * closely resembles what was started in Listing 5.8.
+ *
+ * Listing 5.8 starts talking about HibernateRantDao by injecting a
+ * HibernateTemplate into an otherwise POJO-ish DAO. That example eventually
+ * evolves into one that extends HibernateDaoSupport.
+ *
+ * Although the name is different, this class serves as the example for how to
+ * build Hibernate-based DAOs as described in section 5.4.2.
+ *
+ * @author wallsc
+ */
+public class HibernateRantDaoUsingTemplate implements RantDao {
+ private static final String MOTORIST = Motorist.class.getName();
+ private static final String RANT = Rant.class.getName();
+ private static final String VEHICLE = Vehicle.class.getName();
+
+ public HibernateRantDaoUsingTemplate() {}
+
+ public void saveVehicle(Vehicle vehicle) {
+ hibernateTemplate.saveOrUpdate(vehicle);
+ }
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+ List results = hibernateTemplate.find("from " + VEHICLE
+ + " where state = ? and plateNumber = ?", new Object[] {
+ state, plateNumber });
+
+ if (results.size() > 0) {
+ return (Vehicle) results.get(0);
+ }
+
+ return null; // TODO - Should I throw an exception instead?
+ }
+
+ public void saveRant(Rant rant) {
+ hibernateTemplate.saveOrUpdate(rant);
+ }
+
+ public List getAllRants() {
+ return hibernateTemplate.loadAll(Rant.class);
+ }
+
+ public List getRantsForDay(Date day) {
+ return hibernateTemplate.loadAll(Rant.class);
+ }
+
+ public void saveMotorist(Motorist driver) {
+ hibernateTemplate.saveOrUpdate(driver);
+ }
+
+ public Motorist getDriverById(Integer id) {
+ return (Motorist) hibernateTemplate.load(Motorist.class, id);
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ List results = hibernateTemplate.find("from " + MOTORIST
+ + " where email = ?", email);
+
+ if (results.size() > 0) {
+ return (Motorist) results.get(0);
+ }
+ return null; // TODO - Should I throw an exception instead?
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ // injected
+ private HibernateTemplate hibernateTemplate;
+
+ public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
+ this.hibernateTemplate = hibernateTemplate;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/ibatis/IBatisRantDao.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/ibatis/IBatisRantDao.java
new file mode 100644
index 00000000..dae0f8b3
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/ibatis/IBatisRantDao.java
@@ -0,0 +1,58 @@
+package com.roadrantz.dao.ibatis;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+public class IBatisRantDao extends SqlMapClientDaoSupport implements RantDao {
+
+ public IBatisRantDao() {}
+
+ public void saveRant(Rant rant) {
+ getSqlMapClientTemplate().insert("insertRant", rant);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getAllRants() {
+ return getSqlMapClientTemplate().queryForList("getAllRants", null);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getRantsForDay(Date day) {
+ return getSqlMapClientTemplate().queryForList("getRantsForDay", day);
+ }
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+ Vehicle queryParam = new Vehicle();
+ queryParam.setState(state);
+ queryParam.setPlateNumber(plateNumber);
+
+ return (Vehicle) getSqlMapClientTemplate().queryForObject(
+ "findVehicleByPlate", queryParam);
+ }
+
+ public void saveVehicle(Vehicle vehicle) {
+ getSqlMapClientTemplate().insert("insertVehicle", vehicle);
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ return (Motorist) getSqlMapClientTemplate().queryForObject(
+ "findMotoristByEmail", email);
+ }
+
+ public void saveMotorist(Motorist driver) {
+ Integer primaryKey = (Integer) getSqlMapClientTemplate().insert(
+ "insertMotorist", driver);
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/ibatis/IBatisTemplateRantDao.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/ibatis/IBatisTemplateRantDao.java
new file mode 100644
index 00000000..4ef5a9ac
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/ibatis/IBatisTemplateRantDao.java
@@ -0,0 +1,64 @@
+package com.roadrantz.dao.ibatis;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.orm.ibatis.SqlMapClientTemplate;
+import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+public class IBatisTemplateRantDao implements RantDao {
+
+ public IBatisTemplateRantDao() {}
+
+ public void saveRant(Rant rant) {
+ sqlMapClientTemplate.insert("insertRant", rant);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getAllRants() {
+ return sqlMapClientTemplate.queryForList("getAllRants", null);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getRantsForDay(Date day) {
+ return sqlMapClientTemplate.queryForList("getRantsForDay", day);
+ }
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+ Vehicle queryParam = new Vehicle();
+ queryParam.setState(state);
+ queryParam.setPlateNumber(plateNumber);
+
+ return (Vehicle) sqlMapClientTemplate.queryForObject(
+ "findVehicleByPlate", queryParam);
+ }
+
+ public void saveVehicle(Vehicle vehicle) {
+ sqlMapClientTemplate.insert("insertVehicle", vehicle);
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ return (Motorist)
+ sqlMapClientTemplate.queryForObject("findMotoristByEmail", email);
+ }
+
+ public void saveMotorist(Motorist driver) {
+ Integer primaryKey = (Integer) sqlMapClientTemplate.insert("insertMotorist", driver);
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ // injected
+ private SqlMapClientTemplate sqlMapClientTemplate;
+ public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) {
+ this.sqlMapClientTemplate = sqlMapClientTemplate;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/ConventionalJdbcRantDao.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/ConventionalJdbcRantDao.java
new file mode 100644
index 00000000..cb0109ad
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/ConventionalJdbcRantDao.java
@@ -0,0 +1,220 @@
+package com.roadrantz.dao.jdbc;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Date;
+import java.util.List;
+
+import javax.sql.DataSource;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+public class ConventionalJdbcRantDao implements RantDao {
+ public ConventionalJdbcRantDao() {}
+
+ private static final String RANT_INSERT = "insert into rant (id, rantText, vehicle_id, postedDate) "
+ + "values (null,?,?,?)";
+
+ private static final String MOTORIST_INSERT = "insert into motorist (id, email, password, firstName, lastName) "
+ + "values (null, ?,?,?,?)";
+
+ public void saveRant(Rant rant) {
+ try {
+ Connection conn = dataSource.getConnection();
+ PreparedStatement stmt = conn.prepareStatement("");
+ stmt.setString(1, rant.getRantText());
+ stmt.setInt(2, rant.getVehicle().getId());
+ stmt.setDate(3, new java.sql.Date(rant.getPostedDate().getTime()));
+ stmt.execute();
+ }
+ catch (SQLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public List getAllRants() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public List getRantsForDay(Date day) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void saveVehicle(Vehicle vehicle) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * Inserts a motorist to the database using conventional (e.g., non-Spring)
+ * JDBC.
+ *
+ * From Listing 5.1
+ *
+ * @param motorist
+ * The Motorist object to insert
+ */
+ public void saveMotorist(Motorist motorist) {
+ Connection conn = null;
+ PreparedStatement stmt = null;
+ try {
+ conn = dataSource.getConnection();
+ stmt = conn.prepareStatement(MOTORIST_INSERT);
+
+ stmt.setString(1, motorist.getEmail());
+ stmt.setString(2, motorist.getPassword());
+ stmt.setString(3, motorist.getFirstName());
+ stmt.setString(4, motorist.getLastName());
+ stmt.execute();
+ }
+ catch (SQLException e) {
+ // deal with exception--somehow
+ }
+ finally {
+ try {
+ stmt.close();
+ conn.close();
+ }
+ catch (SQLException e) {}
+ }
+ }
+
+ private static final String MOTORIST_UPDATE = "update motorist "
+ + "set email=?, password=?, firstName=?, lastName=? "
+ + "where id=?";
+
+ /**
+ * Updates a Motorist object in the database, using convention (e.g.,
+ * non-Spring) JDBC
+ *
+ * From Listing 5.2
+ *
+ * @param motorist
+ * The Motorist object to update
+ */
+ public void updateMotorist(Motorist motorist) {
+ Connection conn = null;
+ PreparedStatement stmt = null;
+ try {
+ conn = dataSource.getConnection();
+ stmt = conn.prepareStatement(MOTORIST_UPDATE);
+ stmt.setString(1, motorist.getEmail());
+ stmt.setString(2, motorist.getPassword());
+ stmt.setString(3, motorist.getFirstName());
+ stmt.setString(4, motorist.getLastName());
+ stmt.setInt(5, motorist.getId());
+ stmt.execute();
+ }
+ catch (SQLException e) {
+ // deal with exception--somehow
+ }
+ finally {
+ try {
+ if (stmt != null) {
+ stmt.close();
+ }
+ if (conn != null) {
+ conn.close();
+ }
+ }
+ catch (SQLException e) {}
+ }
+ }
+
+ private static final String MOTORIST_QUERY = "select id, email, password, firstName, lastName "
+ + " from motorist where id=?";
+
+ /**
+ * Retrieves a Motorist from the database using conventional (e.g.,
+ * non-Spring) JDBC.
+ *
+ * From Listing 5.3
+ *
+ * @param id
+ * The ID of the Motorist to retrieve
+ * @return
+ */
+ public Motorist getMotoristById(Integer id) {
+ Connection conn = null;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ conn = dataSource.getConnection();
+ stmt = conn.prepareStatement(MOTORIST_QUERY);
+ stmt.setInt(1, id);
+ rs = stmt.executeQuery();
+ Motorist motorist = null;
+ if (rs.next()) {
+ motorist = new Motorist();
+ motorist.setId(rs.getInt("id"));
+ motorist.setEmail(rs.getString("email"));
+ motorist.setPassword(rs.getString("password"));
+ motorist.setFirstName(rs.getString("firstName"));
+ motorist.setLastName(rs.getString("lastName"));
+ }
+ return motorist;
+ }
+ catch (SQLException e) {}
+ finally {
+ try {
+ if (rs != null) {
+ rs.close();
+ }
+ if (stmt != null) {
+ stmt.close();
+ }
+ if (conn != null) {
+ conn.close();
+ }
+ }
+ catch (SQLException e) {}
+ }
+ return null;
+ }
+
+ private int queryForIdentity() {
+ Connection conn = null;
+ CallableStatement stmt;
+ ResultSet rs;
+
+ try {
+ stmt = conn.prepareCall("call identity()");
+ rs = stmt.executeQuery();
+ if (rs.next()) {
+ return rs.getInt(1);
+ }
+ }
+ catch (SQLException e) {}
+ return 0;
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ private DataSource dataSource;
+
+ public void setDataSource(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/IdentityStoredProcedure.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/IdentityStoredProcedure.java
new file mode 100644
index 00000000..f0246030
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/IdentityStoredProcedure.java
@@ -0,0 +1,32 @@
+package com.roadrantz.dao.jdbc;
+
+import java.sql.Types;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+import org.springframework.jdbc.core.SqlOutParameter;
+import org.springframework.jdbc.object.StoredProcedure;
+
+public class IdentityStoredProcedure extends StoredProcedure {
+ private static final String PROC_NAME = "identity";
+
+ public IdentityStoredProcedure(DataSource ds) {
+ setDataSource(ds);
+ setSql(PROC_NAME);
+
+ // Parameters should be declared in same order here that
+ // they are declared in the stored procedure.
+
+ declareParameter(new SqlOutParameter( "value",
+ Types.INTEGER ) );
+ compile();
+ }
+
+ public Integer getIdentity() {
+ Map map = execute(new HashMap());
+
+ return (Integer) map.get("value");
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcRant.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcRant.java
new file mode 100644
index 00000000..91822107
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcRant.java
@@ -0,0 +1,17 @@
+package com.roadrantz.dao.jdbc;
+
+import com.roadrantz.domain.Rant;
+
+public class JdbcRant extends Rant {
+ public JdbcRant() {}
+
+ private Integer vehicleId;
+
+ public Integer getVehicleId() {
+ return vehicleId;
+ }
+
+ public void setVehicleId(Integer vehicleId) {
+ this.vehicleId = vehicleId;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcRantDao.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcRantDao.java
new file mode 100644
index 00000000..360f2bf8
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcRantDao.java
@@ -0,0 +1,241 @@
+package com.roadrantz.dao.jdbc;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.core.support.JdbcDaoSupport;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+public class JdbcRantDao extends JdbcDaoSupport implements RantDao {
+
+ private static final String RANT_INSERT = "insert into rant (id, rantText, vehicle_id, postedDate) "
+ + "values (null,?,?,?)";
+
+ private static final String RANT_SELECT = "select id, rantText, vehicle_id, postedDate from rant";
+
+ private static final String RANT_FOR_VEHICLE_SELECT = RANT_SELECT
+ + " where vehicle_id = ?";
+
+ private static final String RANT_FOR_DAY_SELECT = RANT_SELECT
+ + " where postedDate=?";
+
+ private static final String VEHICLE_SELECT = "select id, plateNumber, state from vehicle";
+
+ private static final String VEHICLE_BY_ID_SELECT = VEHICLE_SELECT
+ + " where id=?";
+
+ private static final String VEHICLE_BY_PLATE_SELECT = VEHICLE_SELECT
+ + " where state=? and plateNumber=?";
+
+ private static final String VEHICLE_INSERT = "insert into vehicle (id, plateNumber, state, motorist_id) "
+ + "values (null,?,?,?)";
+
+ private static final String MOTORIST_SELECT = "select id, email, password, firstName, lastName from motorist";
+
+ private static final String MOTORIST_BY_EMAIL_SELECT = MOTORIST_SELECT
+ + " where email=?";
+
+ private static final String MOTORIST_BY_ID_SELECT = MOTORIST_SELECT
+ + " where id=?";
+
+ private static final String MOTORIST_INSERT = "insert into motorist (id, email, password, firstName, lastName) "
+ + "values (null, ?,?,?,?)";
+
+ public JdbcRantDao() {}
+
+ /**
+ * Saves a Motorist using Spring's JDBC template.
+ *
+ * From Listing 5.4
+ *
+ * @param motorist
+ * The Motorist to save
+ */
+ public void saveMotorist(Motorist motorist) {
+ getJdbcTemplate().update(
+ MOTORIST_INSERT,
+ new Object[] { motorist.getEmail(),
+ motorist.getPassword(), motorist.getFirstName(),
+ motorist.getLastName() });
+
+ motorist.setId(queryForIdentity());
+ }
+
+ private int queryForIdentity() {
+ return new Integer(getJdbcTemplate().queryForInt("call identity()"));
+ }
+
+ public void saveRant(Rant rant) {
+ getJdbcTemplate()
+ .update(
+ RANT_INSERT,
+ new Object[] { rant.getRantText(),
+ rant.getVehicle().getId(),
+ rant.getPostedDate() });
+
+ rant.setId(queryForIdentity());
+ }
+
+ public void saveVehicle(Vehicle vehicle) {
+ Integer motoristId = vehicle.getMotorist() != null ? vehicle
+ .getMotorist().getId() : null;
+ getJdbcTemplate().update(
+ VEHICLE_INSERT,
+ new Object[] { vehicle.getPlateNumber(),
+ vehicle.getState(), motoristId });
+
+ vehicle.setId(queryForIdentity());
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getAllRants() {
+ return getJdbcTemplate().query(RANT_SELECT, new RowMapper() {
+ public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
+ Rant rant = new Rant();
+ rant.setId(rs.getInt(1));
+ rant.setRantText(rs.getString(2));
+ rant.setPostedDate(rs.getDate(4));
+ Vehicle vehicle = findVehicleById(rs.getInt(3));
+ rant.setVehicle(vehicle);
+ return rant;
+ }
+ });
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getRantsForDay(Date day) {
+ return getJdbcTemplate().query(RANT_FOR_DAY_SELECT, new Object[] { day },
+ new RowMapper() {
+ public Object mapRow(ResultSet rs, int rowNum)
+ throws SQLException {
+ Rant rant = new Rant();
+ rant.setId(rs.getInt(1));
+ rant.setRantText(rs.getString(2));
+ rant.setPostedDate(rs.getDate(4));
+ Vehicle vehicle = findVehicleById(rs.getInt(3));
+ rant.setVehicle(vehicle);
+ return rant;
+ }
+ });
+ }
+
+ public Vehicle findVehicleById(Integer id) {
+
+ List matches = getJdbcTemplate().query(VEHICLE_BY_ID_SELECT,
+ new Object[] { id }, new RowMapper() {
+ public Object mapRow(ResultSet rs, int rowNum)
+ throws SQLException,
+ DataAccessException {
+ Vehicle vehicle = new Vehicle();
+ vehicle.setId(rs.getInt(1));
+ vehicle.setPlateNumber(rs.getString(2));
+ vehicle.setState(rs.getString(3));
+ return vehicle;
+ }
+ });
+
+ return matches.size() > 0 ? (Vehicle) matches.get(0) : null;
+ }
+
+ /**
+ * Retrieves a Motorist by its ID
+ *
+ * From Listing 5.5
+ *
+ * @param id
+ * The ID of the Motorist to retrieve
+ * @return The Motorist
+ */
+ public Motorist getMotoristById(long id) {
+ List matches = getJdbcTemplate().query(MOTORIST_BY_ID_SELECT,
+ new Object[] { Long.valueOf(id) }, new RowMapper() {
+ public Object mapRow(ResultSet rs, int rowNum)
+ throws SQLException,
+ DataAccessException {
+ Motorist motorist = new Motorist();
+
+ motorist.setId(rs.getInt(1));
+ motorist.setEmail(rs.getString(2));
+ motorist.setPassword(rs.getString(3));
+ motorist.setFirstName(rs.getString(4));
+ motorist.setLastName(rs.getString(5));
+ return motorist;
+ }
+ });
+
+ return matches.size() > 0 ? (Motorist) matches.get(0) : null;
+ }
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+
+ List matches = getJdbcTemplate().query(VEHICLE_BY_PLATE_SELECT,
+ new Object[] { state, plateNumber }, new RowMapper() {
+ public Object mapRow(ResultSet rs, int rowNum)
+ throws SQLException,
+ DataAccessException {
+ Vehicle vehicle = new Vehicle();
+ vehicle.setId(rs.getInt(1));
+ vehicle.setPlateNumber(rs.getString(2));
+ vehicle.setState(rs.getString(3));
+ return vehicle;
+ }
+ });
+
+ if (matches.size() == 0) {
+ return null;
+ }
+
+ final Vehicle vehicle = (Vehicle) matches.get(0);
+
+ List rants = getJdbcTemplate().query(RANT_FOR_VEHICLE_SELECT,
+ new Object[] { vehicle.getId() }, new RowMapper() {
+ public Object mapRow(ResultSet rs, int rowNum)
+ throws SQLException {
+ Rant rant = new Rant();
+ rant.setId(rs.getInt(1));
+ rant.setRantText(rs.getString(2));
+ rant.setPostedDate(rs.getDate(4));
+ rant.setVehicle(vehicle);
+ return rant;
+ }
+ });
+
+ vehicle.setRants(rants);
+
+ return vehicle;
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ List matches = getJdbcTemplate().query(MOTORIST_BY_EMAIL_SELECT,
+ new Object[] { email }, new RowMapper() {
+ public Object mapRow(ResultSet rs, int rowNum)
+ throws SQLException,
+ DataAccessException {
+ Motorist motorist = new Motorist();
+
+ motorist.setId(rs.getInt(1));
+ motorist.setEmail(rs.getString(2));
+ motorist.setPassword(rs.getString(3));
+ motorist.setFirstName(rs.getString(4));
+ motorist.setLastName(rs.getString(5));
+ return motorist;
+ }
+ });
+
+ return matches.size() > 0 ? (Motorist) matches.get(0) : null;
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcRantDaoWithSqlObjects.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcRantDaoWithSqlObjects.java
new file mode 100644
index 00000000..9685aa85
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcRantDaoWithSqlObjects.java
@@ -0,0 +1,285 @@
+package com.roadrantz.dao.jdbc;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.core.SqlParameter;
+import org.springframework.jdbc.core.support.JdbcDaoSupport;
+import org.springframework.jdbc.object.MappingSqlQuery;
+import org.springframework.jdbc.object.SqlUpdate;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+public class JdbcRantDaoWithSqlObjects extends JdbcDaoSupport
+ implements RantDao {
+
+ private static final String RANT_INSERT =
+ "insert into rant (id, rantText, vehicle_id, postedDate) " +
+ "values (null,?,?,?)";
+
+ private static final String RANT_SELECT =
+ "select id, rantText, vehicle_id, postedDate from rant";
+
+ private static final String RANT_FOR_DAY_SELECT =
+ RANT_SELECT + " where postedDate=?";
+
+ private static final String VEHICLE_SELECT =
+ "select id, plateNumber, state, motorist_id from vehicle";
+
+ private static final String VEHICLE_BY_ID_SELECT =
+ VEHICLE_SELECT + " where id=?";
+
+ private static final String VEHICLE_BY_PLATE_SELECT =
+ VEHICLE_SELECT + " where state=:state and plateNumber=:plateNumber";
+
+ private static final String VEHICLE_INSERT =
+ "insert into vehicle (id, plateNumber, state, motorist_id) " +
+ "values (null,?,?,?)";
+
+ private static final String MOTORIST_SELECT =
+ "select id, email, password, firstName, lastName from motorist";
+
+ private static final String MOTORIST_BY_EMAIL_SELECT =
+ MOTORIST_SELECT + " where email=?";
+
+ private static final String MOTORIST_BY_ID_SELECT =
+ MOTORIST_SELECT + " where id=?";
+
+ private static final String MOTORIST_INSERT =
+ "insert into motorist (id, email, password, firstName, lastName) " +
+ "values (null, ?,?,?,?)";
+
+ private MotoristByIdQuery motoristByIdQuery;
+ private MotoristByEmailQuery motoristByEmailQuery;
+ private VehicleByIdQuery vehicleByIdQuery;
+ private VehicleByPlateQuery vehicleByPlateQuery;
+ private VehicleInsert vehicleInsert;
+ private RantForDayQuery rantForDayQuery;
+ private RantQuery rantQuery;
+
+ protected void initDao() throws Exception {
+ motoristByIdQuery = new MotoristByIdQuery(getDataSource());
+ motoristByEmailQuery = new MotoristByEmailQuery(getDataSource());
+ vehicleByIdQuery = new VehicleByIdQuery(getDataSource());
+ vehicleByPlateQuery = new VehicleByPlateQuery(getDataSource());
+ rantForDayQuery = new RantForDayQuery(getDataSource());
+ rantQuery = new RantQuery(getDataSource());
+ vehicleInsert = new VehicleInsert(getDataSource());
+ }
+
+ public void saveMotorist(Motorist motorist) {
+ getJdbcTemplate().update(MOTORIST_INSERT,
+ new Object[] { motorist.getEmail(), motorist.getPassword(),
+ motorist.getFirstName(), motorist.getLastName() });
+
+ motorist.setId(queryForIdentity());
+ }
+
+ private int queryForIdentity() {
+ return new Integer(getJdbcTemplate().queryForInt("call identity()"));
+ }
+
+ public void saveRant(Rant rant) {
+ getJdbcTemplate().update(RANT_INSERT,
+ new Object[] {
+ rant.getRantText(),
+ rant.getVehicle().getId(),
+ rant.getPostedDate()
+ });
+
+ rant.setId(queryForIdentity());
+ }
+
+ public void saveVehicle(Vehicle vehicle) {
+ vehicleInsert.insert(vehicle);
+ vehicle.setId(queryForIdentity());
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getAllRants() {
+ List rants = rantQuery.execute();
+ loadVehiclesForRants(rants);
+ return rants;
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getRantsForDay(Date day) {
+ List rants = rantForDayQuery.execute(new Object[] {day});
+ loadVehiclesForRants(rants);
+ return rants;
+ }
+
+ private void loadVehiclesForRants(List rants) {
+ for (Iterator iter = rants.iterator(); iter.hasNext();) {
+ JdbcRant rant = (JdbcRant) iter.next();
+ rant.setVehicle(findVehicleById(rant.getVehicleId()));
+ }
+ }
+
+ public Vehicle findVehicleById(Integer id) {
+ JdbcVehicle vehicle = (JdbcVehicle) vehicleByIdQuery.findObject(id);
+
+ loadMotoristForVehicle(vehicle);
+
+ return vehicle;
+ }
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+ Map parameters = new HashMap();
+ parameters.put("state", state);
+ parameters.put("plateNumber", plateNumber);
+ JdbcVehicle vehicle = (JdbcVehicle)
+ vehicleByPlateQuery.findObjectByNamedParam(parameters);
+
+ loadMotoristForVehicle(vehicle);
+
+ return vehicle;
+ }
+
+ private void loadMotoristForVehicle(JdbcVehicle vehicle) {
+ vehicle.setMotorist(getMotoristById(vehicle.getMotoristId()));
+ }
+
+ public Motorist getMotoristById(Integer id) {
+ return (Motorist) motoristByIdQuery.findObject(id);
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ return (Motorist) motoristByEmailQuery.findObject(email);
+ }
+
+
+ // SQL Objects
+ protected class RantQuery extends MappingSqlQuery {
+ public RantQuery(DataSource dataSource) {
+ this(dataSource, RANT_SELECT);
+ }
+
+ public RantQuery(DataSource dataSource, String query) {
+ super(dataSource, query);
+ }
+
+ protected Object mapRow(ResultSet rs, int rowNum) throws SQLException {
+ JdbcRant rant = new JdbcRant();
+ rant.setId(rs.getInt(1));
+ rant.setRantText(rs.getString(2));
+ rant.setVehicleId(rs.getInt(3));
+ rant.setPostedDate(rs.getDate(4));
+ return rant;
+ }
+ }
+
+ protected class RantForDayQuery extends RantQuery {
+ public RantForDayQuery(DataSource dataSource) {
+ super(dataSource, RANT_FOR_DAY_SELECT);
+ declareParameter(new SqlParameter(Types.DATE));
+ compile();
+ }
+ }
+
+
+ protected class VehicleQuery extends MappingSqlQuery {
+ public VehicleQuery(DataSource dataSource, String query) {
+ super(dataSource, query);
+ }
+
+ protected Object mapRow(ResultSet rs, int rowNum)
+ throws SQLException {
+ JdbcVehicle vehicle = new JdbcVehicle();
+ vehicle.setId(rs.getInt(1));
+ vehicle.setPlateNumber(rs.getString(2));
+ vehicle.setState(rs.getString(3));
+ vehicle.setMotoristId(rs.getInt(4));
+ return vehicle;
+ }
+ }
+
+ protected class VehicleByIdQuery extends VehicleQuery {
+ public VehicleByIdQuery(DataSource dataSource) {
+ super(dataSource, VEHICLE_BY_ID_SELECT);
+ declareParameter(new SqlParameter(Types.INTEGER));
+ compile();
+ }
+ }
+
+ protected class VehicleByPlateQuery extends VehicleQuery {
+ public VehicleByPlateQuery(DataSource dataSource) {
+ super(dataSource, VEHICLE_BY_PLATE_SELECT);
+ declareParameter(new SqlParameter(Types.VARCHAR));
+ declareParameter(new SqlParameter(Types.VARCHAR));
+ compile();
+ }
+ }
+
+
+ protected class MotoristQuery extends MappingSqlQuery {
+ public MotoristQuery(DataSource dataSource, String query) {
+ super(dataSource, query);
+ }
+
+ protected Object mapRow(ResultSet rs, int rowNum)
+ throws SQLException {
+ Motorist motorist = new Motorist();
+
+ motorist.setId(rs.getInt(1));
+ motorist.setEmail(rs.getString(2));
+ motorist.setPassword(rs.getString(3));
+ motorist.setFirstName(rs.getString(4));
+ motorist.setLastName(rs.getString(5));
+
+ return motorist;
+ }
+ }
+
+ protected class MotoristByEmailQuery extends MotoristQuery {
+ public MotoristByEmailQuery(DataSource dataSource) {
+ super(dataSource, MOTORIST_BY_EMAIL_SELECT);
+ declareParameter(new SqlParameter(Types.VARCHAR));
+ compile();
+ }
+ }
+
+ protected class MotoristByIdQuery extends MotoristQuery {
+ public MotoristByIdQuery(DataSource dataSource) {
+ super(dataSource, MOTORIST_BY_ID_SELECT);
+ declareParameter(new SqlParameter(Types.INTEGER));
+ compile();
+ }
+ }
+
+ protected class VehicleInsert extends SqlUpdate {
+ public VehicleInsert(DataSource dataSource) {
+ super(dataSource, VEHICLE_INSERT);
+ declareParameter(new SqlParameter(Types.VARCHAR));
+ declareParameter(new SqlParameter(Types.VARCHAR));
+ declareParameter(new SqlParameter(Types.INTEGER));
+ compile();
+ }
+
+ public void insert(Vehicle vehicle) {
+ update(new Object[] {
+ vehicle.getPlateNumber(),
+ vehicle.getState(),
+ vehicle.getMotorist().getId()
+ });
+ }
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcVehicle.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcVehicle.java
new file mode 100644
index 00000000..2d07fba4
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/JdbcVehicle.java
@@ -0,0 +1,17 @@
+package com.roadrantz.dao.jdbc;
+
+import com.roadrantz.domain.Vehicle;
+
+public class JdbcVehicle extends Vehicle {
+ public JdbcVehicle() {}
+
+ private Integer motoristId;
+
+ public Integer getMotoristId() {
+ return motoristId;
+ }
+
+ public void setMotoristId(Integer motoristId) {
+ this.motoristId = motoristId;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/NamedParameterJdbcRantDao.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/NamedParameterJdbcRantDao.java
new file mode 100644
index 00000000..cb26bf26
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/NamedParameterJdbcRantDao.java
@@ -0,0 +1,76 @@
+package com.roadrantz.dao.jdbc;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+public class NamedParameterJdbcRantDao extends NamedParameterJdbcDaoSupport
+ implements RantDao {
+
+ private static final String MOTORIST_SELECT = "select id, email, password, firstName, lastName from motorist";
+
+ private static final String MOTORIST_INSERT = "insert into motorist (id, email, password, firstName, lastName) "
+ + "values (null, :email, :password, :firstName, :lastName)";
+
+ public NamedParameterJdbcRantDao() {}
+
+ public void saveRant(Rant rant) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public List getAllRants() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public List getRantsForDay(Date day) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void saveVehicle(Vehicle vehicle) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * Saves a Motorist object using Spring's NamedParameterJdbcTemplate.
+ *
+ * From Listing 5.6
+ *
+ * @param motorist
+ * The Motorist object to be saved.
+ */
+ public void saveMotorist(Motorist motorist) {
+ Map parameters = new HashMap();
+ parameters.put("email", motorist.getEmail());
+ parameters.put("password", motorist.getPassword());
+ parameters.put("firstName", motorist.getFirstName());
+ parameters.put("lastName", motorist.getLastName());
+ getNamedParameterJdbcTemplate().update(MOTORIST_INSERT, parameters);
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/SimpleJdbcRantDao.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/SimpleJdbcRantDao.java
new file mode 100644
index 00000000..a2d2b764
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jdbc/SimpleJdbcRantDao.java
@@ -0,0 +1,199 @@
+package com.roadrantz.dao.jdbc;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
+import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+public class SimpleJdbcRantDao extends SimpleJdbcDaoSupport implements RantDao {
+ private static final String RANT_INSERT = "insert into rant (id, rantText, vehicle_id, postedDate) "
+ + "values (null,?,?,?)";
+
+ private static final String RANT_SELECT = "select id, rantText, vehicle_id, postedDate from rant";
+
+ private static final String RANT_FOR_DAY_SELECT = RANT_SELECT
+ + " where postedDate=?";
+
+ private static final String VEHICLE_SELECT = "select id, plateNumber, state from vehicle";
+
+ private static final String VEHICLE_BY_ID_SELECT = VEHICLE_SELECT
+ + " where id=?";
+
+ private static final String VEHICLE_BY_PLATE_SELECT = VEHICLE_SELECT
+ + " where state=? and plateNumber=?";
+
+ private static final String VEHICLE_INSERT = "insert into vehicle (id, plateNumber, state) "
+ + "values (null,?,?)";
+
+ private static final String MOTORIST_SELECT = "select id, email, password, firstName, lastName from motorist";
+
+ private static final String MOTORIST_BY_EMAIL_SELECT = MOTORIST_SELECT
+ + " where email=?";
+
+ private static final String MOTORIST_BY_ID_SELECT = MOTORIST_SELECT
+ + " where id=?";
+
+ private static final String MOTORIST_INSERT = "insert into motorist (id, email, password, firstName, lastName) "
+ + "values (null, ?,?,?,?)";
+
+ public SimpleJdbcRantDao() {}
+
+ public void saveRant(Rant rant) {
+ getSimpleJdbcTemplate().update(RANT_INSERT, rant.getRantText(),
+ rant.getVehicle().getId(), rant.getPostedDate());
+
+ rant.setId(queryForIdentity());
+ }
+
+ public List getAllRants() {
+ return getSimpleJdbcTemplate().query(RANT_SELECT,
+ new ParameterizedRowMapper() {
+ public Rant mapRow(ResultSet rs, int rowNum)
+ throws SQLException {
+ Rant rant = new Rant();
+
+ rant.setId(rs.getInt(1));
+ rant.setRantText(rs.getString(2));
+ rant.setPostedDate(rs.getDate(4));
+ Vehicle vehicle = findVehicleById(rs.getInt(3));
+ rant.setVehicle(vehicle);
+ return rant;
+ }
+ });
+ }
+
+ public Vehicle findVehicleById(Integer id) {
+ return getSimpleJdbcTemplate().queryForObject(VEHICLE_BY_ID_SELECT,
+ new ParameterizedRowMapper() {
+ public Vehicle mapRow(ResultSet rs, int rowNum)
+ throws SQLException {
+ Vehicle vehicle = new Vehicle();
+
+ vehicle.setId(rs.getInt(1));
+ vehicle.setPlateNumber(rs.getString(2));
+ vehicle.setState(rs.getString(3));
+
+ return vehicle;
+ }
+ }, new Object[] { id });
+ }
+
+ public List getRantsForDay(Date day) {
+ return getSimpleJdbcTemplate().query(RANT_FOR_DAY_SELECT,
+ // TODO - THIS IS COMMON...SHOULDN'T BE AN AIC
+ new ParameterizedRowMapper() {
+ public Rant mapRow(ResultSet rs, int rowNum)
+ throws SQLException {
+ Rant rant = new Rant();
+
+ rant.setId(rs.getInt(1));
+ rant.setRantText(rs.getString(2));
+ rant.setPostedDate(rs.getDate(4));
+ Vehicle vehicle = findVehicleById(rs.getInt(3));
+ rant.setVehicle(vehicle);
+ return rant;
+ }
+ }, day);
+ }
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+ List matches = getSimpleJdbcTemplate().query(
+ VEHICLE_BY_PLATE_SELECT,
+ new ParameterizedRowMapper() {
+ public Vehicle mapRow(ResultSet rs, int rowNum)
+ throws SQLException {
+ Vehicle vehicle = new Vehicle();
+
+ vehicle.setId(rs.getInt(1));
+ vehicle.setPlateNumber(rs.getString(2));
+ vehicle.setState(rs.getString(3));
+
+ return vehicle;
+ }
+ }, new Object[] { state, plateNumber });
+
+ return (matches.size() > 0) ? matches.get(0) : null;
+ }
+
+ public void saveVehicle(Vehicle vehicle) {
+ getSimpleJdbcTemplate().update(VEHICLE_INSERT, vehicle.getPlateNumber(),
+ vehicle.getState());
+ vehicle.setId(queryForIdentity());
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ List matches = getSimpleJdbcTemplate().query(
+ MOTORIST_BY_EMAIL_SELECT,
+ new ParameterizedRowMapper() {
+ public Motorist mapRow(ResultSet rs, int rowNum)
+ throws SQLException {
+ Motorist motorist = new Motorist();
+
+ motorist.setId(rs.getInt(1));
+ motorist.setEmail(rs.getString(2));
+ motorist.setPassword(rs.getString(3));
+ motorist.setFirstName(rs.getString(4));
+ motorist.setLastName(rs.getString(5));
+
+ return motorist;
+ }
+ }, email);
+
+ return (matches.size() > 0) ? matches.get(0) : null;
+ }
+
+ /**
+ * Retrieves a Motorist from the database using Spring's SimpleJdbcTemplate,
+ * which allows for handy Java 5 features such as generics, autoboxing, and
+ * variable arguments.
+ *
+ * From Listing 5.7
+ *
+ * @param id
+ * The ID of the Motorist to be retrieved
+ * @return The Motorist
+ */
+ public Motorist getMotoristById(long id) {
+ List matches = getSimpleJdbcTemplate().query(
+ MOTORIST_BY_ID_SELECT,
+ new ParameterizedRowMapper() {
+ public Motorist mapRow(ResultSet rs, int rowNum)
+ throws SQLException {
+ Motorist motorist = new Motorist();
+
+ motorist.setId(rs.getInt(1));
+ motorist.setEmail(rs.getString(2));
+ motorist.setPassword(rs.getString(3));
+ motorist.setFirstName(rs.getString(4));
+ motorist.setLastName(rs.getString(5));
+ return motorist;
+ }
+ }, id);
+
+ return matches.size() > 0 ? matches.get(0) : null;
+ }
+
+ public void saveMotorist(Motorist motorist) {
+ getSimpleJdbcTemplate().update(MOTORIST_INSERT, motorist.getEmail(),
+ motorist.getPassword(), motorist.getFirstName(),
+ motorist.getLastName());
+ motorist.setId(queryForIdentity());
+ }
+
+ private Integer queryForIdentity() {
+ return new Integer(getJdbcTemplate().queryForInt("call Identity()"));
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jpa/JpaRantDao.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jpa/JpaRantDao.java
new file mode 100644
index 00000000..73eb1ae6
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jpa/JpaRantDao.java
@@ -0,0 +1,74 @@
+package com.roadrantz.dao.jpa;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.orm.jpa.support.JpaDaoSupport;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+/**
+ * RantDao implementation that uses JPA by extending Spring's JpaDaoSupport
+ * class and using the supplied JpaTemplate.
+ *
+ * Among other things, JpaTemplate offers several convenience methods (such as
+ * find()) as well as throwing subclasses of Spring's
+ * platform-neutral DataAccessException.
+ *
+ * The downside of using JpaTemplate (and JpaDaoSupport) is that JpaRantDao is
+ * coupled to the Spring API. For an almost Spring-free approach, take a look at
+ * PureJpaRantDao.
+ *
+ * @author wallsc
+ */
+public class JpaRantDao extends JpaDaoSupport implements RantDao {
+
+ public JpaRantDao() {}
+
+ public void saveRant(Rant rant) {
+ getJpaTemplate().persist(rant);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getAllRants() {
+ return getJpaTemplate().find("select r from Rant r");
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getRantsForDay(Date day) {
+ return getJpaTemplate().find(
+ "select r from Rant r where r.postedDate=?1", day);
+ }
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+ List matches = getJpaTemplate()
+ .find(
+ "select v from Vehicle v where v.state=?1 and v.plateNumber=?2",
+ state, plateNumber);
+
+ return (matches.size() > 0) ? (Vehicle) matches.get(0) : null;
+ }
+
+ public void saveVehicle(Vehicle vehicle) {
+ getJpaTemplate().persist(vehicle);
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ List matches = getJpaTemplate().find(
+ "select d from Motorist d where d.email=?1", email);
+
+ return (matches.size() > 0) ? (Motorist) matches.get(0) : null;
+ }
+
+ public void saveMotorist(Motorist driver) {
+ getJpaTemplate().persist(driver);
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jpa/PureJpaRantDao.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jpa/PureJpaRantDao.java
new file mode 100644
index 00000000..02836c6e
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/dao/jpa/PureJpaRantDao.java
@@ -0,0 +1,90 @@
+package com.roadrantz.dao.jpa;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.springframework.stereotype.Repository;
+
+import com.roadrantz.dao.RantDao;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+/**
+ * RantDao implementation that only uses JPA. Contrast this to JpaRantDao which
+ * extends JpaDaoSupport and uses JpaTemplate from Spring's API. The only tie to
+ * Spring in PureJpaRantDao is the Repository annotation, which is used to guide
+ * Spring in converting JPA-specific exceptions to subclasses of Spring's
+ * platform-neutral DataAccessException.
+ *
+ * The EntityManager is injected here by PersistenceAnnotationBeanPostProcessor,
+ * configured in the Spring context along with the entity manager factory.
+ *
+ * Upon looking back at the book, I discovered that I don't discuss this
+ * implementation at all in the book. That's unfortunate, since the Pure JPA
+ * approach is considered the preferred approach to using JPA in Spring.
+ * Nevertheless, here's the implementation for your enjoyment.
+ *
+ * @author wallsc
+ */
+@Repository
+public class PureJpaRantDao implements RantDao {
+ public PureJpaRantDao() {}
+
+ private EntityManager entityManager;
+
+ @PersistenceContext
+ public void setEntityManager(EntityManager entityManager) {
+ this.entityManager = entityManager;
+ }
+
+ public void saveRant(Rant rant) {
+ entityManager.persist(rant);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getAllRants() {
+ return entityManager.createQuery("select r from Rant r").getResultList();
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getRantsForDay(Date day) {
+ return entityManager.createQuery(
+ "select r from Rant r where r.postedDate=?1")
+ .setParameter(1, day).getResultList();
+ }
+
+ public Vehicle findVehicleByPlate(String state, String plateNumber) {
+ List matches = entityManager.createQuery(
+ "select v from Vehicle v where v.state=?1 "
+ + "and v.plateNumber=?2")
+ .setParameter(1, state).setParameter(2, plateNumber)
+ .getResultList();
+
+ return (matches.size() > 0) ? (Vehicle) matches.get(0) : null;
+ }
+
+ public void saveVehicle(Vehicle vehicle) {
+ entityManager.persist(vehicle);
+ }
+
+ public Motorist getMotoristByEmail(String email) {
+ List matches = entityManager.createQuery(
+ "select d from Motorist d where d.email=?1")
+ .setParameter(1, email).getResultList();
+
+ return (matches.size() > 0) ? (Motorist) matches.get(0) : null;
+ }
+
+ public void saveMotorist(Motorist driver) {
+ entityManager.persist(driver);
+ }
+
+ public int getMotoristCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/Motorist.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/Motorist.java
new file mode 100644
index 00000000..3f4833cb
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/Motorist.java
@@ -0,0 +1,112 @@
+package com.roadrantz.domain;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Transient;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+@Entity
+@SuppressWarnings("serial")
+public class Motorist implements Serializable {
+ private Integer id;
+ private String firstName;
+ private String lastName;
+ private String email;
+ private String password;
+ private List vehicles;
+ private Set privileges;
+
+ public Motorist() {
+ privileges = new HashSet();
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ @Id
+ @GeneratedValue(strategy=GenerationType.AUTO)
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ @OneToMany(cascade=CascadeType.ALL,
+ mappedBy="motorist")
+ public List getVehicles() {
+ return vehicles;
+ }
+
+ public void setVehicles(List vehicles) {
+ this.vehicles = vehicles;
+ }
+
+ @Transient
+ public List getRants() {
+ List allRants = new ArrayList();
+
+ for (Vehicle vehicle : vehicles) {
+ allRants.addAll(vehicle.getRants());
+ }
+
+ return allRants;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ @OneToMany(cascade=CascadeType.ALL,
+ fetch=FetchType.LAZY,
+ mappedBy="motorist")
+ public Set getPrivileges() {
+ return privileges;
+ }
+
+ public void setPrivileges(Set privileges) {
+ this.privileges = privileges;
+ }
+
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this);
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/MotoristPrivilege.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/MotoristPrivilege.java
new file mode 100644
index 00000000..9d461867
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/MotoristPrivilege.java
@@ -0,0 +1,52 @@
+package com.roadrantz.domain;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="MOTORIST_PRIVILEGES")
+@SuppressWarnings("serial")
+public class MotoristPrivilege implements Serializable {
+ private Integer id;
+ private Motorist motorist;
+ private String privilege;
+
+ public MotoristPrivilege() {}
+
+ public MotoristPrivilege(String privilege) {
+ this.privilege = privilege;
+ }
+
+ @Id
+ @GeneratedValue(strategy=GenerationType.AUTO)
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ @ManyToOne
+ public Motorist getMotorist() {
+ return motorist;
+ }
+
+ public void setMotorist(Motorist motorist) {
+ this.motorist = motorist;
+ }
+
+ public String getPrivilege() {
+ return privilege;
+ }
+
+ public void setPrivilege(String privilege) {
+ this.privilege = privilege;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/Rant.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/Rant.java
new file mode 100644
index 00000000..5bcec282
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/Rant.java
@@ -0,0 +1,73 @@
+package com.roadrantz.domain;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+@Entity
+@SuppressWarnings("serial")
+public class Rant implements Serializable{
+ private Integer id;
+ private Vehicle vehicle;
+ private String rantText;
+ private Date postedDate;
+
+ public Rant() {}
+
+ @Id
+ @GeneratedValue(strategy=GenerationType.AUTO)
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getRantText() {
+ return rantText;
+ }
+
+ public void setRantText(String rantText) {
+ this.rantText = rantText;
+ }
+
+ @Temporal(TemporalType.DATE)
+ public Date getPostedDate() {
+ return postedDate;
+ }
+
+ public void setPostedDate(Date postedDate) {
+ this.postedDate = postedDate;
+ }
+
+ @ManyToOne
+ public Vehicle getVehicle() {
+ return vehicle;
+ }
+
+ public void setVehicle(Vehicle vehicle) {
+ this.vehicle = vehicle;
+ }
+
+ public boolean equals(Object o) {
+ if (o instanceof Rant) {
+ Rant rant = (Rant) o;
+ return rant.id.equals(this.id);
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ // TODO Auto-generated method stub
+ return super.hashCode();
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/Vehicle.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/Vehicle.java
new file mode 100644
index 00000000..f84c135d
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/domain/Vehicle.java
@@ -0,0 +1,97 @@
+package com.roadrantz.domain;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+@Entity
+@SuppressWarnings("serial")
+public class Vehicle implements Serializable {
+ private Integer id;
+ private String state;
+ private String plateNumber;
+ private Motorist motorist;
+ private List rants;
+
+ public Vehicle() {}
+
+ @Id
+ @GeneratedValue(strategy=GenerationType.AUTO)
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getPlateNumber() {
+ return plateNumber;
+ }
+
+ public void setPlateNumber(String plateNumber) {
+ this.plateNumber = stripNonAlphanumeric(plateNumber);
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String state) {
+ this.state = state.toUpperCase();
+ }
+
+
+ @ManyToOne
+ public Motorist getMotorist() {
+ return motorist;
+ }
+
+ public void setMotorist(Motorist motorist) {
+ this.motorist = motorist;
+ }
+
+ @OneToMany(targetEntity=Rant.class,
+ cascade=CascadeType.ALL,
+ mappedBy="vehicle")
+ public List getRants() {
+ return rants;
+ }
+
+ public void setRants(List rants) {
+ this.rants = rants;
+ }
+
+ private String stripNonAlphanumeric(String in) {
+ if(in == null) { return null; }
+
+ StringBuffer outBuffer = new StringBuffer(in.length());
+
+ for(int i = 0; i < in.length(); i++) {
+ char c = in.charAt(i);
+ if(Character.isLetter(c) || Character.isDigit(c)) {
+ outBuffer.append(Character.toUpperCase(c));
+ }
+ }
+
+ return outBuffer.toString();
+ }
+
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this);
+ }
+
+ public boolean equals(Object o) {
+ return EqualsBuilder.reflectionEquals(this, o);
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/ejb/RantServiceEjb.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/ejb/RantServiceEjb.java
new file mode 100644
index 00000000..4b33427b
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/ejb/RantServiceEjb.java
@@ -0,0 +1,54 @@
+package com.roadrantz.ejb;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.ejb.CreateException;
+
+import org.springframework.ejb.support.AbstractStatelessSessionBean;
+
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+import com.roadrantz.service.MotoristAlreadyExistsException;
+import com.roadrantz.service.RantService;
+
+public class RantServiceEjb
+ extends AbstractStatelessSessionBean
+ implements RantService {
+ public RantServiceEjb() {}
+
+ private RantService rantService;
+ protected void onEjbCreate() throws CreateException {
+ rantService = (RantService) getBeanFactory().getBean("rantService");
+ }
+
+ public void addMotorist(Motorist motorist)
+ throws MotoristAlreadyExistsException {
+ rantService.addMotorist(motorist);
+ }
+
+ public void addRant(Rant rant) {
+ rantService.addRant(rant);
+ }
+
+ public List getRantsForDay(Date date) {
+ return rantService.getRantsForDay(date);
+ }
+
+ public List getRantsForVehicle(Vehicle vehicle) {
+ return rantService.getRantsForVehicle(vehicle);
+ }
+
+ public List getRecentRants() {
+ return rantService.getRecentRants();
+ }
+
+ public void sendDailyRantEmails() {
+ rantService.sendDailyRantEmails();
+ }
+
+ public void sendEmailForVehicle(Vehicle vehicle) {
+ rantService.sendEmailForVehicle(vehicle);
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdb.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdb.java
new file mode 100644
index 00000000..c537b389
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdb.java
@@ -0,0 +1,42 @@
+package com.roadrantz.marketing;
+
+import javax.ejb.EJBException;
+import javax.ejb.MessageDrivenBean;
+import javax.ejb.MessageDrivenContext;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+public class MarketingMdb
+ implements MessageDrivenBean, MessageListener {
+
+ private transient MessageDrivenContext ctx;
+
+ public void setMessageDrivenContext(MessageDrivenContext ctx)
+ throws EJBException {
+ this.ctx = ctx;
+ }
+
+ public void ejbRemove() throws EJBException {
+ }
+
+ public void onMessage(Message message) {
+ MapMessage mapMessage = (MapMessage) message;
+
+ try {
+ SpammedMotorist driver = new SpammedMotorist();
+ driver.setFirstName(mapMessage.getString("firstName"));
+ driver.setLastName(mapMessage.getString("lastName"));
+ driver.setEmail(mapMessage.getString("email"));
+
+ processDriverInfo(driver);
+ } catch (JMSException e) {
+ // handle--somehow
+ }
+ }
+
+ private void processDriverInfo(SpammedMotorist driver) {
+ // ...
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdp.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdp.java
new file mode 100644
index 00000000..a57fd244
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdp.java
@@ -0,0 +1,12 @@
+package com.roadrantz.marketing;
+
+/**
+ * Marketing message-driven POJO, as it appears in listing 10.9.
+ *
+ * @author wallsc
+ */
+public class MarketingMdp implements MarketingService {
+ public MarketingMdp() {}
+
+ public void processDriverInfo(SpammedMotorist driver) {}
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdp10_7.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdp10_7.java
new file mode 100644
index 00000000..f060769c
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdp10_7.java
@@ -0,0 +1,34 @@
+package com.roadrantz.marketing;
+
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+/**
+ * MarketingMdp message-driven POJO, as it appeared in listing 10.7.
+ *
+ * @author wallsc
+ */
+public class MarketingMdp10_7 implements MessageListener {
+
+ public void onMessage(Message message) {
+ MapMessage mapMessage = (MapMessage) message;
+
+ try {
+ SpammedMotorist motorist = new SpammedMotorist();
+ motorist.setFirstName(mapMessage.getString("firstName"));
+ motorist.setLastName(mapMessage.getString("lastName"));
+ motorist.setEmail(mapMessage.getString("email"));
+
+ processMotoristInfo(motorist);
+ }
+ catch (JMSException e) {
+ // handle--somehow
+ }
+ }
+
+ private void processMotoristInfo(SpammedMotorist motorist) {
+ // ...
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdp10_8.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdp10_8.java
new file mode 100644
index 00000000..c445dff2
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingMdp10_8.java
@@ -0,0 +1,25 @@
+package com.roadrantz.marketing;
+
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+
+/**
+ * MarketingMdp, as it appeared in listing 10.8.
+ *
+ * @author wallsc
+ */
+public class MarketingMdp10_8 {
+ public MarketingMdp10_8() {}
+
+ public void processMotoristInfo(MapMessage message) {
+ SpammedMotorist motorist = new SpammedMotorist();
+ try {
+ motorist.setFirstName(message.getString("firstName"));
+ motorist.setLastName(message.getString("lastName"));
+ motorist.setEmail(message.getString("email"));
+ }
+ catch (JMSException e) {
+ // handle this...somehow
+ }
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingReceiverGatewayImpl.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingReceiverGatewayImpl.java
new file mode 100644
index 00000000..27905d2a
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingReceiverGatewayImpl.java
@@ -0,0 +1,17 @@
+package com.roadrantz.marketing;
+
+import org.springframework.jms.core.JmsTemplate;
+
+public class MarketingReceiverGatewayImpl {
+ public MarketingReceiverGatewayImpl() {}
+
+ public SpammedMotorist receivedSpammedDriver() {
+ return (SpammedMotorist) jmsTemplate.receiveAndConvert();
+ }
+
+ //injected
+ private JmsTemplate jmsTemplate;
+ public void setJmsTemplate(JmsTemplate jmsTemplate) {
+ this.jmsTemplate = jmsTemplate;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingReceiverGatewayImpl10_4.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingReceiverGatewayImpl10_4.java
new file mode 100644
index 00000000..33d74dda
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingReceiverGatewayImpl10_4.java
@@ -0,0 +1,38 @@
+package com.roadrantz.marketing;
+
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.jms.support.JmsUtils;
+
+/**
+ * The original version of MarketingReceiverGatewayImpl, as shown in Listing
+ * 10.4. This example evolves as chapter 10 progresses, so this class serves as
+ * a memory of what MarketingReceiverGatewayImpl looked like in listing 10.4.
+ *
+ * @author wallsc
+ */
+public class MarketingReceiverGatewayImpl10_4 {
+ public MarketingReceiverGatewayImpl10_4() {}
+
+ public SpammedMotorist receiveSpammedMotorist() {
+ MapMessage message = (MapMessage) jmsTemplate.receive();
+ SpammedMotorist motorist = new SpammedMotorist();
+ try {
+ motorist.setFirstName(message.getString("firstName"));
+ motorist.setLastName(message.getString("lastName"));
+ motorist.setEmail(message.getString("email"));
+ }
+ catch (JMSException e) {
+ throw JmsUtils.convertJmsAccessException(e);
+ }
+ return motorist;
+ }
+
+ // injected
+ private JmsTemplate jmsTemplate;
+
+ public void setJmsTemplate(JmsTemplate jmsTemplate) {
+ this.jmsTemplate = jmsTemplate;
+ }
+}
\ No newline at end of file
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingService.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingService.java
new file mode 100644
index 00000000..58cc27bd
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MarketingService.java
@@ -0,0 +1,5 @@
+package com.roadrantz.marketing;
+
+public interface MarketingService {
+ public void processDriverInfo(SpammedMotorist driver);
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MotoristMessageConverter.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MotoristMessageConverter.java
new file mode 100644
index 00000000..1c12a402
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/MotoristMessageConverter.java
@@ -0,0 +1,55 @@
+package com.roadrantz.marketing;
+
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.Session;
+
+import org.springframework.jms.support.converter.MessageConversionException;
+import org.springframework.jms.support.converter.MessageConverter;
+
+import com.roadrantz.domain.Motorist;
+
+/**
+ * A message converter to convert MapMessages to/from Motorist objects.
+ *
+ * As shown in listing 10.5.
+ *
+ * @author wallsc
+ */
+public class MotoristMessageConverter implements MessageConverter {
+ public MotoristMessageConverter() {}
+
+ public Object fromMessage(Message message) throws JMSException,
+ MessageConversionException {
+
+ if (!(message instanceof MapMessage)) {
+ throw new MessageConversionException("Message isn't a MapMessage");
+ }
+
+ MapMessage mapMessage = (MapMessage) message;
+ SpammedMotorist motorist = new SpammedMotorist();
+
+ motorist.setFirstName(mapMessage.getString("firstName"));
+ motorist.setLastName(mapMessage.getString("lastName"));
+ motorist.setEmail(mapMessage.getString("email"));
+
+ return motorist;
+ }
+
+ public Message toMessage(Object object, Session session)
+ throws JMSException, MessageConversionException {
+
+ if (!(object instanceof Motorist)) {
+ throw new MessageConversionException("Object isn't a Motorist");
+ }
+
+ Motorist motorist = (Motorist) object;
+ MapMessage message = session.createMapMessage();
+ message.setString("firstName", motorist.getFirstName());
+ message.setString("lastName", motorist.getLastName());
+ message.setString("email", motorist.getEmail());
+
+ return message;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGateway.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGateway.java
new file mode 100644
index 00000000..e1c5a473
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGateway.java
@@ -0,0 +1,7 @@
+package com.roadrantz.marketing;
+
+import com.roadrantz.domain.Motorist;
+
+public interface RantzMarketingGateway {
+ public void sendMotoristInfo(Motorist driver);
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGatewayImpl.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGatewayImpl.java
new file mode 100644
index 00000000..d9f7ada4
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGatewayImpl.java
@@ -0,0 +1,22 @@
+package com.roadrantz.marketing;
+
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.Session;
+
+import org.springframework.jms.core.MessageCreator;
+import org.springframework.jms.core.support.JmsGatewaySupport;
+
+import com.roadrantz.domain.Motorist;
+
+public class RantzMarketingGatewayImpl
+ extends JmsGatewaySupport
+ implements RantzMarketingGateway {
+ public RantzMarketingGatewayImpl() {}
+
+ public void sendMotoristInfo(final Motorist motorist) {
+ getJmsTemplate().convertAndSend(motorist);
+ }
+
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGatewayImpl10_3.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGatewayImpl10_3.java
new file mode 100644
index 00000000..d055d7ad
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGatewayImpl10_3.java
@@ -0,0 +1,45 @@
+package com.roadrantz.marketing;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.Session;
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.jms.core.MessageCreator;
+import com.roadrantz.domain.Motorist;
+
+/**
+ * The original implementation of RantzMarkingGatewayImpl from Listing 10.3.
+ * This class evolves as chapter 10 progresses, so this class serves as a memory
+ * of what it looked like in Listing 10.3.
+ *
+ * @author wallsc
+ */
+public class RantzMarketingGatewayImpl10_3 implements RantzMarketingGateway {
+ public RantzMarketingGatewayImpl10_3() {}
+
+ public void sendMotoristInfo(final Motorist motorist) {
+ jmsTemplate.send(destination, new MessageCreator() {
+ public Message createMessage(Session session) throws JMSException {
+ MapMessage message = session.createMapMessage();
+ message.setString("lastName", motorist.getLastName());
+ message.setString("firstName", motorist.getFirstName());
+ message.setString("email", motorist.getEmail());
+ return message;
+ }
+ });
+ }
+
+ private JmsTemplate jmsTemplate;
+
+ public void setJmsTemplate(JmsTemplate jmsTemplate) {
+ this.jmsTemplate = jmsTemplate;
+ }
+
+ private Destination destination;
+
+ public void setDestination(Destination destination) {
+ this.destination = destination;
+ }
+}
\ No newline at end of file
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGatewayImpl10_6.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGatewayImpl10_6.java
new file mode 100644
index 00000000..ba04ed61
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/RantzMarketingGatewayImpl10_6.java
@@ -0,0 +1,33 @@
+package com.roadrantz.marketing;
+
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.Session;
+
+import org.springframework.jms.core.MessageCreator;
+import org.springframework.jms.core.support.JmsGatewaySupport;
+
+import com.roadrantz.domain.Motorist;
+
+/**
+ * RantzMarketingGatewayImpl as it appeared in listing 10.6.
+ *
+ * @author wallsc
+ */
+public class RantzMarketingGatewayImpl10_6 extends JmsGatewaySupport implements
+ RantzMarketingGateway {
+ public RantzMarketingGatewayImpl10_6() {}
+
+ public void sendMotoristInfo(final Motorist motorist) {
+ getJmsTemplate().send("rantz.marketing.queue", new MessageCreator() {
+ public Message createMessage(Session session) throws JMSException {
+ MapMessage message = session.createMapMessage();
+ message.setString("lastName", motorist.getLastName());
+ message.setString("firstName", motorist.getFirstName());
+ message.setString("email", motorist.getEmail());
+ return message;
+ }
+ });
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/SpammedMotorist.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/SpammedMotorist.java
new file mode 100644
index 00000000..edcfb9a7
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/marketing/SpammedMotorist.java
@@ -0,0 +1,37 @@
+package com.roadrantz.marketing;
+
+import java.io.Serializable;
+
+public class SpammedMotorist implements Serializable {
+ private String firstName;
+ private String lastName;
+ private String email;
+
+ public SpammedMotorist() {}
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/AddRantFormController.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/AddRantFormController.java
new file mode 100644
index 00000000..41a726ee
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/AddRantFormController.java
@@ -0,0 +1,62 @@
+package com.roadrantz.mvc;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.validation.BindException;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.SimpleFormController;
+
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+import com.roadrantz.service.RantService;
+
+public class AddRantFormController extends SimpleFormController {
+ private static final String[] ALL_STATES = { "AL", "AK", "AZ", "AR", "CA",
+ "CO", "CT", "DE", "DC", "FL", "GA", "HI", "ID", "IL", "IN", "IA",
+ "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT",
+ "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR",
+ "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VA", "VT", "WA", "WV",
+ "WI", "WY" };
+
+ public AddRantFormController() {
+ setCommandClass(Rant.class);
+ setCommandName("rant");
+ }
+
+ @Override
+ protected Object formBackingObject(HttpServletRequest request)
+ throws Exception {
+ Rant rantForm = (Rant) super.formBackingObject(request);
+ rantForm.setVehicle(new Vehicle());
+ return rantForm;
+ }
+
+ @Override
+ protected Map referenceData(HttpServletRequest request) throws Exception {
+ Map referenceData = new HashMap();
+
+ referenceData.put("states", ALL_STATES);
+
+ return referenceData;
+ }
+
+ @Override
+ protected ModelAndView onSubmit(Object command, BindException bindException)
+ throws Exception {
+
+ Rant rant = (Rant) command;
+ rantService.addRant(rant);
+
+ return new ModelAndView(getSuccessView());
+ }
+
+ // injected
+ private RantService rantService;
+
+ public void setRantService(RantService rantService) {
+ this.rantService = rantService;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/DayForm.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/DayForm.java
new file mode 100644
index 00000000..a83d6439
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/DayForm.java
@@ -0,0 +1,16 @@
+package com.roadrantz.mvc;
+
+import java.util.Date;
+
+public class DayForm {
+ private Date day;
+ public DayForm() {}
+
+ public Date getDay() {
+ return day;
+ }
+
+ public void setDay(Date day) {
+ this.day = day;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/HomePageController.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/HomePageController.java
new file mode 100644
index 00000000..a13f9ac1
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/HomePageController.java
@@ -0,0 +1,30 @@
+package com.roadrantz.mvc;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.AbstractController;
+
+import com.roadrantz.service.RantService;
+
+public class HomePageController extends AbstractController {
+ public HomePageController() {}
+
+ protected ModelAndView handleRequestInternal(
+ HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
+
+ List recentRants = rantService.getRecentRants();
+
+ return new ModelAndView("home", "rants", recentRants);
+ }
+
+ // injected
+ private RantService rantService;
+ public void setRantService(RantService rantService) {
+ this.rantService = rantService;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/MotoristRegistrationController.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/MotoristRegistrationController.java
new file mode 100644
index 00000000..8da7294d
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/MotoristRegistrationController.java
@@ -0,0 +1,82 @@
+package com.roadrantz.mvc;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.validation.BindException;
+import org.springframework.validation.Errors;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.AbstractWizardFormController;
+
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Vehicle;
+import com.roadrantz.service.RantService;
+
+public class MotoristRegistrationController extends AbstractWizardFormController {
+ public MotoristRegistrationController() {
+ setCommandClass(Motorist.class);
+ setCommandName("motorist");
+ }
+
+ protected Object formBackingObject(HttpServletRequest request)
+ throws Exception {
+ Motorist formMotorist = new Motorist();
+ List vehicles = new ArrayList();
+ vehicles.add(new Vehicle());
+ formMotorist.setVehicles(vehicles);
+ return formMotorist;
+ }
+
+ protected Map referenceData(HttpServletRequest request,
+ Object command, Errors errors, int page) throws Exception {
+
+ Motorist motorist = (Motorist) command;
+ Map refData = new HashMap();
+
+ if(page == 1 && request.getParameter("_target1") != null) {
+ refData.put("nextVehicle", motorist.getVehicles().size() - 1);
+ }
+
+ return refData;
+ }
+
+ protected void postProcessPage(HttpServletRequest request,
+ Object command, Errors errors, int page) throws Exception {
+
+ Motorist motorist = (Motorist) command;
+
+ if(page == 1 && request.getParameter("_target1") != null) {
+ motorist.getVehicles().add(new Vehicle());
+ } }
+
+ protected ModelAndView processFinish(HttpServletRequest request,
+ HttpServletResponse response, Object command, BindException errors)
+ throws Exception {
+
+ Motorist motorist = (Motorist) command;
+
+ // the last vehicle is always blank...remove it
+ motorist.getVehicles().remove(motorist.getVehicles().size() - 1);
+
+ rantService.addMotorist(motorist);
+
+ return new ModelAndView(getSuccessView(), "motorist", motorist);
+ }
+
+ // injected
+ private RantService rantService;
+ public void setRantService(RantService rantService) {
+ this.rantService = rantService;
+ }
+
+ // returns the last page as the success view
+ private String getSuccessView() {
+ return getPages()[getPages().length-1];
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/OldRantsForDayController.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/OldRantsForDayController.java
new file mode 100644
index 00000000..b7d008ef
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/OldRantsForDayController.java
@@ -0,0 +1,32 @@
+package com.roadrantz.mvc;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.validation.BindException;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.AbstractCommandController;
+
+import com.roadrantz.service.RantService;
+
+public class OldRantsForDayController extends AbstractCommandController {
+ public OldRantsForDayController() {
+ setCommandClass(DayForm.class);
+ }
+
+ protected ModelAndView handle(HttpServletRequest request,
+ HttpServletResponse response, Object command,
+ BindException errors) throws Exception {
+
+ DayForm day = (DayForm) command;
+
+ return new ModelAndView("dayRants", "rants",
+ rantService.getRantsForDay(day.getDay()));
+ }
+
+ // injected
+ private RantService rantService;
+ public void setRantService(RantService rantService) {
+ this.rantService = rantService;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantExcelView.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantExcelView.java
new file mode 100644
index 00000000..d88f9f65
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantExcelView.java
@@ -0,0 +1,59 @@
+package com.roadrantz.mvc;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFDataFormat;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.springframework.web.servlet.view.document.AbstractExcelView;
+
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Vehicle;
+
+public class RantExcelView extends AbstractExcelView {
+ protected void buildExcelDocument(Map model, HSSFWorkbook workbook,
+ HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
+
+ Collection rants = (Collection) model.get("rants");
+ Vehicle vehicle = (Vehicle) model.get("vehicle");
+
+ HSSFSheet sheet = createSheet(workbook, vehicle.getPlateNumber());
+
+ HSSFCellStyle cellStyle = workbook.createCellStyle();
+ cellStyle.setDataFormat(
+ HSSFDataFormat.getBuiltinFormat("m/d/yy h:mm"));
+
+ int rowNum = 1;
+ for (Iterator iter = rants.iterator(); iter.hasNext();) {
+ Rant rant = (Rant) iter.next();
+ rowNum = addRantRow(sheet, cellStyle, rowNum, rant);
+ }
+ }
+
+ private int addRantRow(HSSFSheet sheet, HSSFCellStyle cellStyle,
+ int rowNum, Rant rant) {
+ HSSFRow row = sheet.createRow(rowNum++);
+ row.createCell((short) 0).setCellValue(rant.getPostedDate());
+ row.createCell((short) 1).setCellValue(rant.getRantText());
+ row.getCell((short) 1).setCellStyle(cellStyle);
+ return rowNum;
+ }
+
+ private HSSFSheet createSheet(HSSFWorkbook workbook,
+ String plateNumber) {
+ HSSFSheet sheet = workbook.createSheet("Rants for " + plateNumber);
+
+ HSSFRow header = sheet.createRow(0);
+ header.createCell((short) 0).setCellValue("Date");
+ header.createCell((short) 1).setCellValue("Text");
+ return sheet;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantPdfView.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantPdfView.java
new file mode 100644
index 00000000..e36ea651
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantPdfView.java
@@ -0,0 +1,43 @@
+package com.roadrantz.mvc;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.web.servlet.view.document.AbstractPdfView;
+
+import com.lowagie.text.Document;
+import com.lowagie.text.Table;
+import com.lowagie.text.pdf.PdfWriter;
+import com.roadrantz.domain.Rant;
+
+public class RantPdfView extends AbstractPdfView {
+ protected void buildPdfDocument(Map model, Document document,
+ PdfWriter pdfWriter, HttpServletRequest request,
+ HttpServletResponse response) throws Exception {
+
+ List rants = (List) model.get("rants");
+ Table rantTable = new Table(4);
+ rantTable.setWidth(90);
+ rantTable.setBorderWidth(1);
+
+ rantTable.addCell("State");
+ rantTable.addCell("Plate");
+ rantTable.addCell("Date Posted");
+ rantTable.addCell("Text");
+
+ for (Iterator iter = rants.iterator(); iter.hasNext();) {
+ Rant rant = (Rant) iter.next();
+
+ rantTable.addCell(rant.getVehicle().getState());
+ rantTable.addCell(rant.getVehicle().getPlateNumber());
+ rantTable.addCell(rant.getPostedDate().toString());
+ rantTable.addCell(rant.getRantText());
+ }
+
+ document.add(rantTable);
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantRssView.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantRssView.java
new file mode 100644
index 00000000..9bed1644
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantRssView.java
@@ -0,0 +1,106 @@
+package com.roadrantz.mvc;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.web.servlet.view.AbstractView;
+
+import com.roadrantz.domain.Rant;
+import com.sun.syndication.feed.synd.SyndContent;
+import com.sun.syndication.feed.synd.SyndContentImpl;
+import com.sun.syndication.feed.synd.SyndEntry;
+import com.sun.syndication.feed.synd.SyndEntryImpl;
+import com.sun.syndication.feed.synd.SyndFeed;
+import com.sun.syndication.feed.synd.SyndFeedImpl;
+import com.sun.syndication.io.SyndFeedOutput;
+
+public class RantRssView extends AbstractView {
+ private String author;
+ private String title;
+ private String description;
+ private String link;
+
+ public RantRssView() {}
+
+ protected void renderMergedOutputModel(Map model,
+ HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
+
+ SyndFeed feed = createFeed();
+ List rants = (List)model.get("rants");
+ List entries = new ArrayList();
+
+ for (Iterator iter = rants.iterator(); iter.hasNext();) {
+ Rant rant = (Rant) iter.next();
+ entries.add(createEntry(rant));
+ }
+
+ feed.setEntries(entries);
+
+ SyndFeedOutput output = new SyndFeedOutput();
+ output.output(feed, response.getWriter());
+ }
+
+ private SyndEntry createEntry(Rant rant) {
+ SyndEntry entry = new SyndEntryImpl();
+
+ entry.setTitle("title?");
+ entry.setLink("link");
+ entry.setPublishedDate(rant.getPostedDate());
+ SyndContent content = new SyndContentImpl();
+ content.setType("text/html");
+ content.setValue(rant.getRantText());
+ entry.setDescription(content);
+
+ return entry;
+ }
+
+ private SyndFeed createFeed() {
+ SyndFeed feed = new SyndFeedImpl();
+ feed.setFeedType("rss_1.0");
+ feed.setAuthor(author);
+ feed.setTitle(title);
+ feed.setDescription(description);
+ feed.setLink(link);
+
+ return feed;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getLink() {
+ return link;
+ }
+
+ public void setLink(String link) {
+ this.link = link;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantValidator.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantValidator.java
new file mode 100644
index 00000000..668ec9da
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantValidator.java
@@ -0,0 +1,43 @@
+package com.roadrantz.mvc;
+
+import org.apache.oro.text.perl.Perl5Util;
+import org.springframework.validation.Errors;
+import org.springframework.validation.ValidationUtils;
+import org.springframework.validation.Validator;
+
+import com.roadrantz.domain.Rant;
+
+public class RantValidator implements Validator {
+ public boolean supports(Class clazz) {
+ return clazz.equals(Rant.class);
+ }
+
+ public void validate(Object command, Errors errors) {
+ Rant rant = (Rant) command;
+
+ ValidationUtils.rejectIfEmpty(
+ errors, "vehicle.state", "required.state",
+ "State is required.");
+
+ ValidationUtils.rejectIfEmpty(
+ errors, "vehicle.plateNumber", "required.plateNumber",
+ "The license plate number is required.");
+
+ ValidationUtils.rejectIfEmptyOrWhitespace(
+ errors, "rantText", "required.rantText",
+ "You must enter some rant text.");
+
+ validatePlateNumber(rant.getVehicle().getPlateNumber(), errors);
+ }
+
+ private static final String PLATE_REGEXP =
+ "/[a-z0-9]{2,6}/i";
+
+ private void validatePlateNumber(String plateNumber, Errors errors) {
+ Perl5Util perl5Util = new Perl5Util();
+ if(!perl5Util.match(PLATE_REGEXP, plateNumber)) {
+ errors.reject("invalid.plateNumber",
+ "Invalid license plate number.");
+ }
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantsForDayController.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantsForDayController.java
new file mode 100644
index 00000000..f2eccd48
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantsForDayController.java
@@ -0,0 +1,43 @@
+package com.roadrantz.mvc;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.throwaway.ThrowawayController;
+
+import com.roadrantz.domain.Rant;
+import com.roadrantz.service.RantService;
+
+public class RantsForDayController implements ThrowawayController {
+ private int month;
+ private int day;
+ private int year;
+
+ public ModelAndView execute() throws Exception {
+ Date date = new Date(month, day, year);
+
+ List dayRants = rantService.getRantsForDay(date);
+
+ return new ModelAndView("dayRants", "rants",
+ dayRants);
+ }
+
+ public void setDay(int day) {
+ this.day = day;
+ }
+
+ public void setMonth(int month) {
+ this.month = month;
+ }
+
+ public void setYear(int year) {
+ this.year = year;
+ }
+
+ // injected
+ private RantService rantService;
+ public void setRantService(RantService rantService) {
+ this.rantService = rantService;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantsForVehicleController.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantsForVehicleController.java
new file mode 100644
index 00000000..025d40f4
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/mvc/RantsForVehicleController.java
@@ -0,0 +1,50 @@
+package com.roadrantz.mvc;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.validation.BindException;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.mvc.AbstractCommandController;
+
+import com.roadrantz.domain.Vehicle;
+import com.roadrantz.service.RantService;
+
+public class RantsForVehicleController extends AbstractCommandController {
+ private static final String BASE_VIEW_NAME = "vehicleRants";
+
+ public RantsForVehicleController() {
+ setCommandClass(Vehicle.class);
+ setCommandName("vehicle");
+ }
+
+ protected ModelAndView handle(HttpServletRequest request,
+ HttpServletResponse response, Object command,
+ BindException errors) throws Exception {
+
+ Vehicle vehicle = (Vehicle) command;
+
+ Map model = errors.getModel();
+ model.put("rants", rantService.getRantsForVehicle(vehicle));
+ model.put("vehicle", vehicle);
+
+ return new ModelAndView(getViewName(request), model);
+ }
+
+ private String getViewName(HttpServletRequest request) {
+ String requestUri = request.getRequestURI();
+ String extension = "." + requestUri.substring(requestUri.length() - 3);
+ if(".htm".equals(extension)) { extension=""; }
+ return BASE_VIEW_NAME + extension;
+ }
+
+ // injected
+ private RantService rantService;
+ public void setRantService(RantService rantService) {
+ this.rantService = rantService;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/security/PasswordEncodingAdvice.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/security/PasswordEncodingAdvice.java
new file mode 100644
index 00000000..104ae1fb
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/security/PasswordEncodingAdvice.java
@@ -0,0 +1,47 @@
+package com.roadrantz.security;
+
+import org.acegisecurity.providers.dao.SaltSource;
+import org.acegisecurity.providers.encoding.PasswordEncoder;
+import org.apache.log4j.Logger;
+import org.aspectj.lang.ProceedingJoinPoint;
+
+import com.roadrantz.domain.Motorist;
+
+public class PasswordEncodingAdvice {
+ private static final Logger LOGGER =
+ Logger.getLogger(PasswordEncodingAdvice.class);
+
+ public PasswordEncodingAdvice() {}
+
+ public Object encodeMotoristPassword(ProceedingJoinPoint pjp)
+ throws Throwable {
+
+ Object[] args = pjp.getArgs();
+ if(args.length != 1 || !(args[0] instanceof Motorist)) {
+ return pjp.proceed();
+ }
+
+ Motorist motorist = (Motorist) args[0];
+ String encodedPassword =
+ passwordEncoder.encodePassword(motorist.getPassword().trim(),
+ saltSource.getSalt(null));
+
+ LOGGER.debug("SALT: " + saltSource.getSalt(null));
+ LOGGER.debug("UNENCODED: " + motorist.getPassword());
+ LOGGER.debug("ENCODED: " + encodedPassword);
+
+ motorist.setPassword(encodedPassword);
+ return pjp.proceed(new Object[] {motorist});
+}
+
+ // injected
+ private PasswordEncoder passwordEncoder;
+ public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
+ this.passwordEncoder = passwordEncoder;
+ }
+
+ private SaltSource saltSource;
+ public void setSaltSource(SaltSource saltSource) {
+ this.saltSource = saltSource;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/service/DailyRantEmailJob.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/service/DailyRantEmailJob.java
new file mode 100644
index 00000000..c01378be
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/service/DailyRantEmailJob.java
@@ -0,0 +1,27 @@
+package com.roadrantz.service;
+
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.springframework.scheduling.quartz.QuartzJobBean;
+
+/**
+ * A Quartz job bean to call the RantService's sendDailyRantEmails() method.
+ *
+ * As shown in Listing 12.4, page 460.
+ *
+ * @author craig.walls
+ */
+public class DailyRantEmailJob extends QuartzJobBean {
+ public DailyRantEmailJob() {}
+
+ protected void executeInternal(JobExecutionContext jobContext)
+ throws JobExecutionException {
+ rantService.sendDailyRantEmails();
+ }
+
+ // injected
+ private RantService rantService;
+ public void setRantService(RantService rantService) {
+ this.rantService = rantService;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/service/DailyRantEmailTask.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/service/DailyRantEmailTask.java
new file mode 100644
index 00000000..8e9c604b
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/service/DailyRantEmailTask.java
@@ -0,0 +1,24 @@
+package com.roadrantz.service;
+
+import java.util.TimerTask;
+
+/**
+ * Java timer task to call the RantService's sendDailyRantEmails.
+ *
+ * As shown in Listing 12.3, page 458.
+ *
+ * @author craig.walls
+ */
+public class DailyRantEmailTask extends TimerTask {
+ public DailyRantEmailTask() {}
+
+ public void run() {
+ rantService.sendDailyRantEmails();
+ }
+
+ // injected
+ private RantService rantService;
+ public void setRantService(RantService rantService) {
+ this.rantService = rantService;
+ }
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/service/MotoristAlreadyExistsException.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/service/MotoristAlreadyExistsException.java
new file mode 100644
index 00000000..f4dbaa03
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/service/MotoristAlreadyExistsException.java
@@ -0,0 +1,5 @@
+package com.roadrantz.service;
+
+public class MotoristAlreadyExistsException extends Exception {
+ public MotoristAlreadyExistsException() {}
+}
diff --git a/springInAction/RoadRantz/src/main/java/com/roadrantz/service/RantService.java b/springInAction/RoadRantz/src/main/java/com/roadrantz/service/RantService.java
new file mode 100644
index 00000000..460052e1
--- /dev/null
+++ b/springInAction/RoadRantz/src/main/java/com/roadrantz/service/RantService.java
@@ -0,0 +1,24 @@
+package com.roadrantz.service;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.jmx.export.annotation.ManagedOperation;
+import org.springframework.jmx.export.annotation.ManagedResource;
+
+import com.roadrantz.domain.Rant;
+import com.roadrantz.domain.Motorist;
+import com.roadrantz.domain.Vehicle;
+
+@ManagedResource(objectName="rantz:name=RantService") // Annotation added in Listing 12.5
+public interface RantService {
+ public void addRant(Rant rant);
+ public List getRecentRants();
+ public void addMotorist(Motorist motorist) throws MotoristAlreadyExistsException;
+ public List