├── README.md └── examples ├── BinaryTreeMap ├── BTreeMap.java └── BTreeMapNode.java ├── BookingApp ├── RunMe.java ├── booking.db ├── booking.properties └── booking │ ├── client │ ├── BookingController.java │ ├── BookingGui.java │ └── BookingView.java │ ├── db │ ├── BookingException.java │ ├── DBFactory.java │ ├── DBMain.java │ ├── Data.java │ ├── DuplicateKeyException.java │ ├── FieldInfo.java │ ├── LockManager.java │ └── RecordNotFoundException.java │ └── server │ ├── DBRMIServer.java │ └── DBRMIServerImpl.java ├── CalculatorApp ├── Calculator.java ├── CalculatorGUI.java ├── CalculatorScreen.java ├── MyCalculator.java ├── Screen.java └── SwingScreen.java ├── ChatApp ├── ChatClient.java └── ChatServer.java ├── Others ├── Course.java ├── MyMap.java ├── NineNine.java ├── ObjectCount.java ├── Student.java ├── Teacher.java └── TestMyMap.java └── ThermosApp ├── CoolWaterContainer.java ├── Heater.java ├── HotWaterContainer.java ├── TestThermos.java ├── Thermos.java ├── ThermosGui.java └── WaterContainer.java /README.md: -------------------------------------------------------------------------------- 1 | # UML超新手入門 2 | 3 | UML... 4 | 5 | 如果以食物來比喻的話,對開發人員來說,UML是一種比食之無味、棄之可惜的雞肋還要尷尬的東西。它通常是老鳥用來告誡菜鳥一種「很重要」的工具,只不過老鳥在大部份的情況下,還是會忘記UML。還有雖然它一定會出現在系統專案開發文件裡面,用來告訴客戶「我們的專案是很有質感的」,只不過這些UML圖型永遠跟實際的程式碼有很大的距離。 6 | 7 | 這種你想忽略可是又不能逃離它的UML,很適合出現在「超新手入門」系列專欄,搭配Java程式設計語言,用不一樣的方式來認識UML。 8 | 9 | # 目錄 10 | 11 | * [UML超新手入門(1)UML概論](http://www.codedata.com.tw/java/umltutorial-01/) 12 | * [UML超新手入門(2)類別圖型 - 類別節點](http://www.codedata.com.tw/java/umltutorial-02/) 13 | * [UML超新手入門(3)類別圖型 - 結合關係](http://www.codedata.com.tw/java/umltutorial-03/) 14 | * [UML超新手入門(4)套件圖型](http://www.codedata.com.tw/java/umltutorial-04/) 15 | * [UML超新手入門(5)物件圖型](http://www.codedata.com.tw/java/umltutorial-05/) 16 | * [UML超新手入門(6)元件圖型](http://www.codedata.com.tw/java/umltutorial-06/) 17 | * [UML超新手入門(7)佈署圖型](http://www.codedata.com.tw/java/umltutorial-07/) 18 | * [UML超新手入門(8)循序圖型](http://www.codedata.com.tw/java/umltutorial-08/) 19 | * [UML超新手入門(9)合作圖型](http://www.codedata.com.tw/java/umltutorial-09/) 20 | * [UML超新手入門(10)狀態圖型](http://www.codedata.com.tw/java/umltutorial-10/) 21 | * [UML超新手入門(11)活動圖型](http://www.codedata.com.tw/java/umltutorial-11/) 22 | -------------------------------------------------------------------------------- /examples/BinaryTreeMap/BTreeMap.java: -------------------------------------------------------------------------------- 1 | public class BTreeMap { 2 | BTreeMapNode topNode = null; 3 | 4 | public void add(Comparable key, Object value) { 5 | if (topNode == null) { 6 | topNode = new BTreeMapNode(key, value); 7 | } else { 8 | topNode.add(key, value); 9 | } 10 | } 11 | 12 | public Object get(Comparable key) { 13 | Object result = null; 14 | 15 | if (topNode != null) { 16 | result = topNode.find(key); 17 | } 18 | 19 | return result; 20 | } 21 | 22 | public static void main(String args[]) { 23 | BTreeMap btm = new BTreeMap(); 24 | btm.add("5", "Five"); 25 | btm.add("8", "Eight"); 26 | btm.add("9", "Eight"); 27 | btm.add("2", "Eight"); 28 | btm.add("32", "Eight"); 29 | 30 | System.out.println(btm.get("9")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/BinaryTreeMap/BTreeMapNode.java: -------------------------------------------------------------------------------- 1 | public class BTreeMapNode { 2 | private Comparable key; 3 | private Object value; 4 | private BTreeMapNode nodes[] = new BTreeMapNode[2]; 5 | 6 | public BTreeMapNode(Comparable key, Object value) { 7 | this.key = key; 8 | this.value = value; 9 | } 10 | 11 | public Object find(Comparable key) { 12 | System.out.println("Find"); 13 | if (this.key.compareTo(key) == 0) { 14 | return this.value; 15 | } else { 16 | return findSubNodeForKey(selectSubNode(key), key); 17 | } 18 | } 19 | 20 | private int selectSubNode(Comparable key) { 21 | int result = 0; 22 | 23 | if (key.compareTo(this.key) >= 0){ 24 | result = 1; 25 | } 26 | 27 | return result; 28 | } 29 | 30 | private Object findSubNodeForKey(int node, Comparable key) { 31 | if (nodes[node] == null) { 32 | return null; 33 | } else { 34 | return nodes[node].find(key); 35 | } 36 | } 37 | 38 | public void add(Comparable key, Object value) { 39 | if (key.compareTo(this.key) == 0) { 40 | this.value = value; 41 | } else { 42 | addSubNode(selectSubNode(key), key, value); 43 | } 44 | } 45 | 46 | private void addSubNode(int node, Comparable key, Object value) { 47 | if (nodes[node] == null) { 48 | nodes[node] = new BTreeMapNode(key, value); 49 | } else { 50 | nodes[node].add(key, value); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/BookingApp/RunMe.java: -------------------------------------------------------------------------------- 1 | import booking.client.*; 2 | import booking.db.*; 3 | import booking.server.*; 4 | 5 | import java.util.Properties; 6 | import java.io.FileInputStream; 7 | 8 | /** 9 | * Main program. Depend on command line arguments, it can start rmi 10 | * service, remote GUI client or run in standalone mode. 11 | */ 12 | public class RunMe { 13 | /** 14 | * The standard start entry. 15 | * 16 | * @param args String array, take zero or one command line argument: 17 | *
  • zero : network client.
  • 18 | *
  • "server" : create rmi service.
  • 19 | *
  • "alone" : standalone mode.
  • 20 | */ 21 | public static void main(String args[]) { 22 | args = new String[]{"alone"}; 23 | int argLen = args.length; 24 | 25 | // MVC component 26 | BookingGui gui; // view 27 | BookingController sc; // controller 28 | DBMain data; // model 29 | 30 | // Default configuration 31 | String dbFile = "booking.db"; 32 | String remoteHost = "localhost"; 33 | String rmiPortNumber = "1234"; 34 | String rmiServiceName = "DatabaseService"; 35 | 36 | Properties p = new Properties(); 37 | 38 | // Read configuration from suncertify.properties 39 | try { 40 | p.load(new FileInputStream("booking.properties")); 41 | dbFile = p.getProperty("dbFile"); 42 | remoteHost = p.getProperty("remoteHost"); 43 | rmiPortNumber = p.getProperty("rmiPortNumber"); 44 | rmiServiceName = p.getProperty("rmiServiceName"); 45 | } catch (Exception ex) { 46 | System.out.println("Read properties error, use default configuration"); 47 | } 48 | 49 | try { 50 | if (argLen == 0) { 51 | // No argument, remote client 52 | data = new DBFactory().getDB( 53 | remoteHost, rmiPortNumber, rmiServiceName); 54 | gui = new BookingGui(data); 55 | sc = new BookingController(data, gui); 56 | } else if (argLen == 1) { 57 | // One argument 58 | // "server" for remote server, "along" for single mode 59 | if (args[0].equals("server")) { 60 | DBRMIServer db_rmi = 61 | new DBRMIServer(dbFile, remoteHost, 62 | rmiPortNumber, rmiServiceName); 63 | } else if (args[0].equals("alone")) { 64 | data = new DBFactory().getDB(dbFile); 65 | gui = new BookingGui(data); 66 | sc = new BookingController(data, gui); 67 | } 68 | } else { 69 | // Show usage 70 | System.out.println("Usage:"); 71 | System.out.println(" Remote client:"); 72 | System.out.println(" java -jar runme.jar"); 73 | System.out.println(" Remote server:"); 74 | System.out.println(" java -jar runme.jar server"); 75 | System.out.println(" Standalone:"); 76 | System.out.println(" java -jar runme.jar along"); 77 | } 78 | } catch (Exception ex) { 79 | System.out.println(ex); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /examples/BookingApp/booking.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/macdidi5/UMLTutorial/c842d48fbdd34ae6bd096b4c410ea6ca66746072/examples/BookingApp/booking.db -------------------------------------------------------------------------------- /examples/BookingApp/booking.properties: -------------------------------------------------------------------------------- 1 | dbFile=booking.db 2 | remoteHost=localhost 3 | rmiPortNumber=1234 4 | rmiServiceName=DatabaseService -------------------------------------------------------------------------------- /examples/BookingApp/booking/client/BookingController.java: -------------------------------------------------------------------------------- 1 | package booking.client; 2 | 3 | import booking.db.DBMain; 4 | import booking.db.BookingException; 5 | 6 | /** 7 | * This class provides controller of the MVC. 8 | */ 9 | public class BookingController { 10 | private DBMain data; 11 | private BookingView bv; 12 | 13 | /** 14 | * Creates new BookingController. 15 | * 16 | * @param data The model of the MVC. 17 | * @param bv The view of the MVC. 18 | * @exception BookingException Thrown if any error occur. 19 | */ 20 | public BookingController(DBMain data, BookingView bv) 21 | throws BookingException { 22 | this.data = data; 23 | this.bv = bv; 24 | 25 | try { 26 | bv.setUserGestureListener(this); 27 | } catch (Exception ex) { 28 | throw new BookingException( 29 | "Exception occure in BookingController constructor."); 30 | } 31 | } 32 | 33 | /** 34 | * Create data user gesture callback method called by 35 | * the suncertify view in response to the create data 36 | * button click on the GUI or equivalent user interface 37 | * action - create the data in the model 38 | * 39 | * @param data String array represent new data. 40 | */ 41 | public void handleAddGesture(String data[]) 42 | throws BookingException { 43 | 44 | try { 45 | System.out.println("BookingController: handleAddGesture"); 46 | this.data.create(data); 47 | } catch (Exception ex) { 48 | throw new BookingException(ex.getMessage()); 49 | } 50 | } 51 | 52 | /** 53 | * Update data user gesture callback method called by 54 | * the suncertify view in response to the update data 55 | * button click on the GUI or equivalent user interface 56 | * action - update the data in the model 57 | * 58 | * @param recNo Record number. 59 | * @param data String array represent new data. 60 | */ 61 | public void handleUpdateGesture(int recNo, String data[]) 62 | throws BookingException { 63 | 64 | try { 65 | System.out.println("BookingController: handleUpdateGesture: " + recNo); 66 | this.data.update(recNo, data); 67 | } catch (Exception ex) { 68 | throw new BookingException(ex.getMessage()); 69 | } 70 | } 71 | 72 | /** 73 | * Delete data user gesture callback method called by the suncertify 74 | * view in response to the delete data button click on the GUI or 75 | * equivalent user interface action - delete the data in the model 76 | * 77 | * @param recNo Record number. 78 | */ 79 | public void handleDeleteGesture(int recNo) 80 | throws BookingException { 81 | 82 | try { 83 | System.out.println("BookingController: handleDeleteGesture: " + recNo); 84 | this.data.delete(recNo); 85 | } catch (Exception ex) { 86 | throw new BookingException(ex.getMessage()); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /examples/BookingApp/booking/client/BookingGui.java: -------------------------------------------------------------------------------- 1 | package booking.client; 2 | 3 | import java.awt.*; 4 | import java.awt.event.*; 5 | import javax.swing.*; 6 | import javax.swing.table.*; 7 | import javax.swing.event.*; 8 | 9 | import java.util.*; 10 | import java.io.Serializable; 11 | 12 | import java.rmi.RemoteException; 13 | import java.rmi.server.UnicastRemoteObject; 14 | 15 | import booking.db.*; 16 | 17 | /** 18 | * This class provides client GUIs and view of the MVC. 19 | */ 20 | public class BookingGui 21 | extends UnicastRemoteObject 22 | implements BookingView, Serializable { 23 | 24 | // MVC 25 | private DBMain data; 26 | private BookingController bc; 27 | 28 | // GUI components 29 | private JFrame frame; 30 | private Container contentPane; 31 | private JPanel uPan = new JPanel(); 32 | private JPanel lPan = new JPanel(); 33 | private JPanel functionPan = new JPanel(); 34 | private JButton helpBt = new JButton("Help"); 35 | private JButton seaBt = new JButton("Search"); 36 | private JButton addBt = new JButton("Add"); 37 | private JButton updBt = new JButton("Update"); 38 | private JButton delBt = new JButton("Delete"); 39 | private JButton bookBt = new JButton("Booking"); 40 | private JButton exitBt = new JButton("Exit"); 41 | private JPanel subconPan = new JPanel(); 42 | private JLabel recNoLb = new JLabel("Record number"); 43 | private JLabel nameLb = new JLabel("Subcontractor name"); 44 | private JLabel locationLb = new JLabel("City"); 45 | private JLabel specialtiesLb = new JLabel("Types of work performed"); 46 | private JLabel sizeLb = new JLabel("Number of staff"); 47 | private JLabel rateLb = new JLabel("Hourly charge"); 48 | private JLabel ownerLb = new JLabel("Owner"); 49 | private JTextField recNoTf = new JTextField(); 50 | private JTextField nameTf = new JTextField(); 51 | private JTextField locationTf = new JTextField(); 52 | private JTextField specialtiesTf = new JTextField(); 53 | private JTextField sizeTf = new JTextField(); 54 | private JTextField rateTf = new JTextField(); 55 | private JTextField ownerTf = new JTextField(); 56 | private JPanel tablePan = new JPanel(); 57 | private String tableHeaders[] = 58 | {"Subcontractor name", "City", "Types of work performed", 59 | "Number of staff", "Hourly charge", "Owner", "Record number"}; 60 | private JTable table; 61 | private JScrollPane tableSp; 62 | private DefaultTableModel tableModel; 63 | private JPanel statusPan = new JPanel(); 64 | 65 | // Status bar 66 | private JLabel statusLb = new JLabel("Status", SwingConstants.CENTER); 67 | private JTextField statusTf= new JTextField(); 68 | 69 | /** 70 | * This constructor take a model object and construct user interface. 71 | * 72 | * @param db The model object. 73 | * @exception RemoteException Thrown if any error occur. 74 | */ 75 | public BookingGui(DBMain data) throws RemoteException { 76 | try { 77 | this.data = data; 78 | this.data.addChangeListener(this); 79 | buildDisplay(); 80 | addListeners(); 81 | } catch (Exception ex) { 82 | throw new RemoteException(ex.getMessage()); 83 | } 84 | } 85 | 86 | // Private methods 87 | 88 | private void buildDisplay(){ 89 | frame = new JFrame("Subcontractor Tool"); 90 | buildFunctionPanel(); 91 | buildSubconPanel(); 92 | buildTablePanel(); 93 | buildStatusPanel(); 94 | 95 | uPan.setLayout(new BorderLayout()); 96 | uPan.add(functionPan, BorderLayout.NORTH); 97 | uPan.add(subconPan, BorderLayout.CENTER); 98 | 99 | lPan.setLayout(new BorderLayout()); 100 | lPan.add(tablePan, BorderLayout.CENTER); 101 | lPan.add(statusPan, BorderLayout.SOUTH); 102 | 103 | contentPane = frame.getContentPane(); 104 | contentPane.setLayout(new BorderLayout()); 105 | contentPane.add(uPan, BorderLayout.NORTH); 106 | contentPane.add(lPan, BorderLayout.CENTER); 107 | 108 | frame.pack(); 109 | frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 110 | frame.setVisible(true); 111 | } 112 | 113 | private void buildFunctionPanel() { 114 | functionPan.setLayout(new FlowLayout()); 115 | functionPan.add(helpBt); 116 | functionPan.add(seaBt); 117 | functionPan.add(addBt); 118 | functionPan.add(updBt); 119 | functionPan.add(delBt); 120 | functionPan.add(bookBt); 121 | functionPan.add(exitBt); 122 | } 123 | 124 | private void buildSubconPanel() { 125 | ownerTf.setEditable(false); 126 | recNoTf.setEditable(false); 127 | subconPan.setLayout(new GridLayout(7,2)); 128 | subconPan.add(recNoLb); 129 | subconPan.add(recNoTf); 130 | subconPan.add(nameLb); 131 | subconPan.add(nameTf); 132 | subconPan.add(locationLb); 133 | subconPan.add(locationTf); 134 | subconPan.add(specialtiesLb); 135 | subconPan.add(specialtiesTf); 136 | subconPan.add(sizeLb); 137 | subconPan.add(sizeTf); 138 | subconPan.add(rateLb); 139 | subconPan.add(rateTf); 140 | subconPan.add(ownerLb); 141 | subconPan.add(ownerTf); 142 | } 143 | 144 | private void buildTablePanel() { 145 | tablePan.setLayout(new BorderLayout()); 146 | tableModel = new DefaultTableModel(tableHeaders, 10); 147 | table = new JTable(tableModel); 148 | tableSp = new JScrollPane(table); 149 | tablePan.add(tableSp, BorderLayout.CENTER); 150 | Dimension dim = new Dimension(500, 150); 151 | table.setPreferredScrollableViewportSize(dim); 152 | table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 153 | ListSelectionModel rowSM = table.getSelectionModel(); 154 | rowSM.addListSelectionListener(new ChooseRecord(rowSM)); 155 | } 156 | 157 | private void buildStatusPanel() { 158 | statusPan.setLayout(new BorderLayout()); 159 | statusPan.add(statusLb, BorderLayout.NORTH); 160 | statusPan.add(statusTf, BorderLayout.CENTER); 161 | } 162 | 163 | private void addListeners() { 164 | helpBt.addActionListener(new HelpAction()); 165 | seaBt.addActionListener(new SearchAction()); 166 | addBt.addActionListener(new AddAction()); 167 | updBt.addActionListener(new UpdateAction()); 168 | delBt.addActionListener(new DeleteAction()); 169 | bookBt.addActionListener(new BookingAction()); 170 | exitBt.addActionListener(new ExitAction()); 171 | } 172 | 173 | private void clearSubconPanel() { 174 | recNoTf.setText(""); 175 | nameTf.setText(""); 176 | locationTf.setText(""); 177 | specialtiesTf.setText(""); 178 | sizeTf.setText(""); 179 | rateTf.setText(""); 180 | ownerTf.setText(""); 181 | } 182 | 183 | /** 184 | * Refresh field data on subcontractor panel. 185 | * 186 | * @param record The String array of record. 187 | */ 188 | public void refreshSubconPanel(String record[]){ 189 | nameTf.setText(record[0]); 190 | locationTf.setText(record[1]); 191 | specialtiesTf.setText(record[2]); 192 | sizeTf.setText(record[3]); 193 | rateTf.setText(record[4]); 194 | ownerTf.setText(record[5]); 195 | } 196 | 197 | /** 198 | * Refresh table data on table panel. 199 | * 200 | * @param records The String two array of records. 201 | */ 202 | public void refreshTablePanel(String records[][]) { 203 | tableModel.setDataVector(records, tableHeaders); 204 | } 205 | 206 | /** 207 | * Refresh table record on table panel. 208 | * 209 | * @param record The String array of record. 210 | */ 211 | public void refreshTableRecord(int recNo, String record[]) { 212 | int rowCount = tableModel.getRowCount(); 213 | String recNoStr = String.valueOf(recNo); 214 | 215 | for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) { 216 | String tableRecNo = (String)tableModel.getValueAt(rowIndex, 6); 217 | 218 | if (recNoStr.equals(tableRecNo)) { 219 | for (int i = 0; i < record.length; i++) { 220 | tableModel.setValueAt(record[i], rowIndex, i); 221 | } 222 | break; 223 | } 224 | } 225 | } 226 | 227 | /** 228 | * Update status message. 229 | * 230 | * @param msg The status message string. 231 | */ 232 | public void updateStatus(String msg) { 233 | statusTf.setText(msg); 234 | } 235 | 236 | /** 237 | * Get record data on subcontractor panel. 238 | * 239 | * @return The String array of record. 240 | */ 241 | public String[] getRecordOnPan() { 242 | String result[] = new String[6]; 243 | result[0] = nameTf.getText(); 244 | result[1] = locationTf.getText(); 245 | result[2] = specialtiesTf.getText(); 246 | result[3] = sizeTf.getText(); 247 | result[4] = rateTf.getText(); 248 | result[5] = ownerTf.getText(); 249 | 250 | return result; 251 | } 252 | 253 | /** 254 | * Adds requester to the list of objects to be notified of user 255 | * gestures entered through a user interface such as a GUI. 256 | * 257 | * @param bc The controller object. 258 | */ 259 | public void setUserGestureListener(BookingController bc) 260 | throws BookingException, RemoteException { 261 | this.bc = bc; 262 | } 263 | 264 | /** 265 | * Callback method to handle data state change notification 266 | * from the suncertify model. 267 | * 268 | * @param recNo Record number. 269 | * @param data String array represent new data. 270 | */ 271 | public void handleDataChange(Integer recNo, String data[]) 272 | throws BookingException { 273 | System.out.println("BookingGui: handleDataChange: " + recNo); 274 | 275 | // Determine subcontractor panel refresh 276 | String panelData[] = getRecordOnPan(); 277 | if (panelData[0].equals(data[0]) && panelData[1].equals(data[1])) { 278 | refreshSubconPanel(data); 279 | } 280 | 281 | refreshTableRecord(recNo.intValue(), data); 282 | } 283 | 284 | /** 285 | * This inner class Search the database. 286 | */ 287 | public class SearchAction implements ActionListener { 288 | /** 289 | * User click Search button. 290 | * 291 | * @param e The ActionEvent object 292 | */ 293 | public void actionPerformed(ActionEvent e) { 294 | String record[] = getRecordOnPan(); 295 | try { 296 | int match[] = data.find(record); 297 | String records[][] = new String[match.length][7]; 298 | 299 | for (int i = 0; i < match.length; i++) { 300 | String rec[] = data.read(match[i]); 301 | System.arraycopy(rec, 0, records[i], 0, rec.length); 302 | records[i][6] = String.valueOf(match[i]); 303 | } 304 | 305 | refreshTablePanel(records); 306 | updateStatus(match.length + " records matched."); 307 | } catch (Exception ex) { 308 | updateStatus(ex.getMessage()); 309 | } 310 | } 311 | } 312 | 313 | /** 314 | * This inner class add new record to database. 315 | */ 316 | public class AddAction implements ActionListener { 317 | /** 318 | * User click Add button. 319 | * 320 | * @param e The ActionEvent object 321 | */ 322 | public void actionPerformed(ActionEvent e) { 323 | String record[] = getRecordOnPan(); 324 | // Avoid exist owner value 325 | record[5] = ""; 326 | 327 | try { 328 | bc.handleAddGesture(record); 329 | updateStatus("Record added."); 330 | } catch (Exception ex) { 331 | updateStatus(ex.getMessage()); 332 | } 333 | } 334 | } // End of AddAction 335 | 336 | /** 337 | * This inner class update record to database. 338 | */ 339 | public class UpdateAction implements ActionListener { 340 | /** 341 | * User click Update button. 342 | * 343 | * @param e The ActionEvent object 344 | */ 345 | public void actionPerformed(ActionEvent e) { 346 | String record[] = getRecordOnPan(); 347 | String searchKey[] = new String[6]; 348 | System.arraycopy(record, 0, searchKey, 0, 2); 349 | searchKey[0] = searchKey[0].trim(); 350 | searchKey[1] = searchKey[1].trim(); 351 | 352 | try { 353 | int match[] = data.find(searchKey); 354 | 355 | if (match.length > 1) { 356 | updateStatus("More than one match record."); 357 | return; 358 | } else if (match.length == 0) { 359 | updateStatus("Record not found."); 360 | return; 361 | } 362 | 363 | bc.handleUpdateGesture(match[0], record); 364 | updateStatus("Record updated."); 365 | } catch (Exception ex) { 366 | updateStatus(ex.getMessage()); 367 | } 368 | } 369 | } // End of UpdateAction 370 | 371 | /** 372 | * This inner class delete record to database. 373 | */ 374 | public class DeleteAction implements ActionListener { 375 | /** 376 | * User click Delete button. 377 | * 378 | * @param e The ActionEvent object 379 | */ 380 | public void actionPerformed(ActionEvent e) { 381 | String record[] = getRecordOnPan(); 382 | try { 383 | int match[] = data.find(record); 384 | if (match.length == 1) { 385 | bc.handleDeleteGesture(match[0]); 386 | clearSubconPanel(); 387 | updateStatus("Record deleted."); 388 | } else { 389 | updateStatus("More than one match record."); 390 | } 391 | } catch (Exception ex) { 392 | updateStatus(ex.getMessage()); 393 | } 394 | } 395 | } // End of DeleteAction 396 | 397 | /** 398 | * This inner class write the database. 399 | */ 400 | public class BookingAction implements ActionListener { 401 | /** 402 | * User click Booking button. 403 | * 404 | * @param e The ActionEvent object 405 | */ 406 | public void actionPerformed(ActionEvent e) { 407 | JTextField ownerTf; 408 | String mes; 409 | 410 | String record[] = getRecordOnPan(); 411 | 412 | try { 413 | int match[] = data.find(record); 414 | 415 | if (match.length > 1) { 416 | updateStatus("More than one match record."); 417 | return; 418 | } else if (match.length == 0) { 419 | updateStatus("Record not found."); 420 | return; 421 | } 422 | 423 | ownerTf = new JTextField(); 424 | ownerTf.setText(record[5]); 425 | mes = "Enter customer id"; 426 | 427 | int result = JOptionPane.showOptionDialog( 428 | frame, new Object[] {mes, ownerTf}, 429 | "Booking", JOptionPane.OK_CANCEL_OPTION, 430 | JOptionPane.PLAIN_MESSAGE, 431 | null, null, null); 432 | 433 | if (result == JOptionPane.OK_OPTION) { 434 | record[5] = ownerTf.getText(); 435 | bc.handleUpdateGesture(match[0], record); 436 | updateStatus("Subcontractor booked."); 437 | } 438 | } catch (Exception ex) { 439 | updateStatus(ex.getMessage()); 440 | } 441 | } 442 | } // End of BookingAction 443 | 444 | /** 445 | * This inner class exit application. 446 | */ 447 | public class ExitAction implements ActionListener { 448 | /** 449 | * User click exit button. 450 | * 451 | * @param e The ActionEvent object 452 | */ 453 | public void actionPerformed(ActionEvent e) { 454 | System.exit(0); 455 | } 456 | } // End of ExitAction 457 | 458 | /** 459 | * This inner class show user help dialog. 460 | */ 461 | public class HelpAction implements ActionListener { 462 | /** 463 | * User click help button. 464 | * 465 | * @param e The ActionEvent object 466 | */ 467 | public void actionPerformed(ActionEvent e) { 468 | JTextPane pane = new JTextPane(); 469 | JScrollPane scroller = new JScrollPane(); 470 | scroller.getViewport().add(pane); 471 | JDialog dialog = new JDialog(); 472 | dialog.getContentPane().add(scroller); 473 | dialog.pack(); 474 | dialog.setSize(800, 500); 475 | dialog.setVisible(true); 476 | String htmlDocument = "userguide.html"; 477 | 478 | try { 479 | java.net.URL url = 480 | new java.net.URL("file:docs" + 481 | System.getProperty("file.separator") + 482 | htmlDocument); 483 | pane.setPage(url); 484 | } 485 | catch(Exception ex) { 486 | updateStatus(ex.getMessage()); 487 | } 488 | } 489 | } // End of HelpAction 490 | 491 | /** 492 | * This inner class implements ListSelectionListener and handles 493 | * the selection of JTable cell. Once a cell is selected, 494 | * record is automatically filled in the constractor panel. 495 | */ 496 | public class ChooseRecord implements ListSelectionListener { 497 | ListSelectionModel model; 498 | String record[] = new String[7]; 499 | 500 | /** 501 | * Sets the ListSelectionModel 502 | * 503 | * @param lsm The ListSelectionModel object 504 | */ 505 | public ChooseRecord(ListSelectionModel lsm) { 506 | model = lsm; 507 | } 508 | 509 | /** 510 | * Invokes when a different line is selected and sets values to 511 | * constractor panel. If successful, a choose record message 512 | * shown in status area. If failed, no message is shown. 513 | * 514 | * @param lse The ListSelectionEvent object 515 | */ 516 | public void valueChanged(ListSelectionEvent lse) { 517 | if(!lse.getValueIsAdjusting()) { 518 | int rowIndex = model.getMinSelectionIndex(); 519 | 520 | if(rowIndex == -1) { 521 | return ; 522 | } 523 | 524 | for (int i = 0; i < record.length; i++) { 525 | record[i] = 526 | (String)tableModel.getValueAt(rowIndex, i); 527 | } 528 | 529 | nameTf.setText(record[0]); 530 | locationTf.setText(record[1]); 531 | specialtiesTf.setText(record[2]); 532 | sizeTf.setText(record[3]); 533 | rateTf.setText(record[4]); 534 | ownerTf.setText(record[5]); 535 | recNoTf.setText(record[6]); 536 | updateStatus("Choose record."); 537 | } 538 | } 539 | } // End of ChooseRecord 540 | } -------------------------------------------------------------------------------- /examples/BookingApp/booking/client/BookingView.java: -------------------------------------------------------------------------------- 1 | package booking.client; 2 | 3 | import booking.db.BookingException; 4 | 5 | import java.rmi.Remote; 6 | import java.rmi.RemoteException; 7 | 8 | /** 9 | * The interface of view in MVC. 10 | */ 11 | public interface BookingView extends Remote { 12 | // Adds requester to the list of objects to be notified of user 13 | // gestures entered through a user interface such as a GUI. 14 | void setUserGestureListener(BookingController sc) 15 | throws BookingException, RemoteException; 16 | 17 | // Callback method to handle data state change notification 18 | // from the suncertify model 19 | void handleDataChange(Integer recNo, String data[]) 20 | throws BookingException, RemoteException; 21 | 22 | // Update status message. 23 | void updateStatus(String msg) 24 | throws RemoteException; 25 | } 26 | -------------------------------------------------------------------------------- /examples/BookingApp/booking/db/BookingException.java: -------------------------------------------------------------------------------- 1 | package booking.db; 2 | 3 | /** 4 | * This class defines the database exception used 5 | * in this application to indicate application wrong. 6 | */ 7 | 8 | public class BookingException extends Exception { 9 | /** 10 | * Creates new BookingException without detail message. 11 | */ 12 | public BookingException() { 13 | super(); 14 | } 15 | 16 | /** 17 | * Constructs an BookingException with the specified 18 | * detail message. 19 | * 20 | * @param msg the detail message. 21 | */ 22 | public BookingException(String msg) { 23 | super(msg); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/BookingApp/booking/db/DBFactory.java: -------------------------------------------------------------------------------- 1 | package booking.db; 2 | 3 | import java.rmi.*; 4 | import java.rmi.registry.*; 5 | 6 | /** 7 | * Provides local or remote database connections. 8 | */ 9 | public class DBFactory { 10 | private static final String dbFile = "db-2x1.db"; 11 | private static final String UNEXPECTED = 12 | "DBFactory - Unexpected database access problem: "; 13 | 14 | /** 15 | * Return DBMain object, open data file in current working directory. 16 | * 17 | * @return Instance of database. 18 | * @exception BookingException Thrown if cannot open data file. 19 | */ 20 | public DBMain getDB() throws BookingException { 21 | return new Data(dbFile); 22 | } 23 | 24 | /** 25 | * Open specify local data file and return DBMain object. 26 | * 27 | * @param dbFile The data file. 28 | * @return Instance of database. 29 | * @exception BookingException Thrown if cannot open data file. 30 | */ 31 | public DBMain getDB(String dbFile) throws BookingException { 32 | return new Data(dbFile); 33 | } 34 | 35 | /** 36 | * Lookup remote rmi server and return DBMain object. 37 | * 38 | * @param host The rmi server. 39 | * @param port The rmi service port number. 40 | * @param serviceName The rmi service name. 41 | * @return Instance of database. 42 | * @exception BookingException Thrown if cannot open data connection. 43 | */ 44 | public DBMain getDB(String host, String port, String serviceName) 45 | throws BookingException { 46 | 47 | String lookupString = "rmi://" + host + ":" + port + 48 | "/" + serviceName; 49 | try { 50 | return (DBMain)Naming.lookup(lookupString); 51 | } catch (Exception ex) { 52 | throw new BookingException(lookupString + "\n" + 53 | UNEXPECTED + "\n" + ex); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /examples/BookingApp/booking/db/DBMain.java: -------------------------------------------------------------------------------- 1 | package booking.db; 2 | 3 | import booking.client.BookingView; 4 | 5 | import java.rmi.Remote; 6 | import java.rmi.RemoteException; 7 | 8 | /** 9 | * Supplied interface. 10 | * Extends java.rmi.Remote for rmi approach. 11 | * Add addChangeListener method for apply MVC design pattern. 12 | */ 13 | public interface DBMain extends Remote { 14 | // Reads a record from the file. Returns an array where each 15 | // element is a record value. 16 | public String [] read(int recNo) throws RecordNotFoundException, RemoteException; 17 | // Modifies the fields of a record. The new value for field n 18 | // appears in data[n]. 19 | public void update(int recNo, String [] data) 20 | throws RecordNotFoundException, RemoteException; 21 | // Deletes a record, making the record number and associated disk 22 | // storage available for reuse. 23 | public void delete(int recNo) throws RecordNotFoundException, RemoteException; 24 | // Returns an array of record numbers that match the specified 25 | // criteria. Field n in the database file is described by 26 | // criteria[n]. A null value in criteria[n] matches any field 27 | // value. A non-null value in criteria[n] matches any field 28 | // value that begins with criteria[n]. (For example, "Fred" 29 | // matches "Fred" or "Freddy".) 30 | public int [] find(String [] criteria) throws RecordNotFoundException, RemoteException; 31 | // Creates a new record in the database (possibly reusing a 32 | // deleted entry). Inserts the given data, and returns the record 33 | // number of the new record. 34 | public int create(String [] data) throws DuplicateKeyException, RemoteException; 35 | // Locks a record so that it can only be updated or deleted by this client. 36 | // If the specified record is already locked, the current thread gives up 37 | // the CPU and consumes no CPU cycles until the record is unlocked. 38 | public void lock(int recNo) throws RecordNotFoundException, RemoteException; 39 | // Releases the lock on a record. 40 | public void unlock(int recNo) throws RecordNotFoundException, RemoteException; 41 | // Determines if a record is currenly locked. Returns true if the 42 | // record is locked, false otherwise. 43 | public boolean isLocked(int recNo) throws RecordNotFoundException, RemoteException; 44 | // Adds requestor to the list of objects to be notified when an 45 | // object model alters state. 46 | public void addChangeListener(BookingView sv) throws BookingException, RemoteException; 47 | } 48 | -------------------------------------------------------------------------------- /examples/BookingApp/booking/db/Data.java: -------------------------------------------------------------------------------- 1 | package booking.db; 2 | 3 | import booking.client.*; 4 | 5 | import java.io.*; 6 | import java.util.*; 7 | 8 | /** 9 | * This class provides the database services. 10 | */ 11 | public class Data implements DBMain, Serializable { 12 | private static final byte LIVE_RECORD = 0; 13 | private static final byte DELETED_RECORD = 1; 14 | private static final String UNEXPECTED = 15 | "Data: Unexpected database access problem - \n"; 16 | private int headerLen = 4 + 4 + 2; 17 | private final int MAGIC = 513; 18 | private RandomAccessFile db; 19 | private int recordLen; 20 | private int fieldCount; 21 | private FieldInfo fieldInfo[]; 22 | 23 | // Store BookingView object 24 | private ArrayList changeListeners = new ArrayList(10); 25 | 26 | /** 27 | * This constructor opens an existing database given the name 28 | * of the disk file containing it. 29 | * 30 | * @param dbname The name of the database file to open. 31 | * @exception BookingException 32 | */ 33 | public Data(String dbName) throws BookingException { 34 | try { 35 | File f = new File(dbName); 36 | if (f.exists() && f.canRead() && f.canWrite()) { 37 | db = new RandomAccessFile(f, "rw"); 38 | 39 | if (db.readInt() != MAGIC) { 40 | throw new BookingException( 41 | "Data: corrupted database file - " + dbName); 42 | } 43 | 44 | recordLen = db.readInt(); // value is 182 45 | fieldCount = db.readShort(); // value is 6 46 | fieldInfo = new FieldInfo[fieldCount]; 47 | 48 | for (int count = 0; count < fieldCount; count++) { 49 | headerLen += 2; 50 | int fieldNameLen = db.readShort(); 51 | headerLen += fieldNameLen; 52 | byte temp[] = new byte[fieldNameLen]; 53 | db.read(temp); 54 | int fieldLen = db.readShort(); 55 | fieldInfo[count] = new FieldInfo(new String(temp), fieldLen); 56 | headerLen += 2; 57 | } 58 | // headerLen is 70 59 | } else { 60 | throw new BookingException("Data: Non-existant or " + 61 | "inaccessible file" + dbName); 62 | } 63 | } catch (Exception e) { 64 | throw new BookingException(UNEXPECTED + e); 65 | } 66 | } 67 | 68 | /** 69 | * Adds requestor to the list of objects to be notified when an 70 | * object model alters state. 71 | * 72 | * @param sv The suncertify view object. 73 | */ 74 | public void addChangeListener(BookingView bv) 75 | throws BookingException { 76 | changeListeners.add(bv); 77 | } 78 | 79 | /** 80 | * This method notifies all registered BookingView listeners 81 | * that data has changed. 82 | */ 83 | private void fireModelChangeEvent(Integer recNo, String data[]) 84 | throws BookingException { 85 | BookingView sv; 86 | 87 | for (int i=0; i 0) { 237 | result = new int[aList.size()]; 238 | for (int i = 0; i < result.length; i++) { 239 | result[i] = ((Integer)aList.get(i)).intValue(); 240 | } 241 | } else { 242 | throw new RecordNotFoundException(); 243 | } 244 | 245 | return result; 246 | } 247 | 248 | /** 249 | * Creates a new record in the database (possibly reusing a 250 | * deleted entry) 251 | * 252 | * @param data The value of the record. 253 | * @return int The record number of the new record. 254 | * @exception DuplicateKeyException thrown if duplicate key occure. 255 | */ 256 | public synchronized int create(String [] data) 257 | throws DuplicateKeyException { 258 | 259 | String searchKey[] = new String[6]; 260 | System.arraycopy(data, 0, searchKey, 0, 2); 261 | searchKey[0] = searchKey[0].trim(); 262 | searchKey[1] = searchKey[1].trim(); 263 | 264 | int writeRecNo = 0; 265 | int recordCount = 0; 266 | 267 | // Check duplicate key 268 | try { 269 | if (find(searchKey).length > 0) { 270 | throw new DuplicateKeyException( 271 | "Attempt to create a duplicate key record."); 272 | } 273 | } catch (RecordNotFoundException enfe) { 274 | // do nothing 275 | } catch (Exception ex) { 276 | throw new DuplicateKeyException(UNEXPECTED + ex); 277 | } 278 | 279 | try { 280 | // Search deleted record 281 | recordCount = getRecordCount(); 282 | 283 | if (recordCount > 0) { 284 | for (int i = 1; i <= recordCount; i++) { 285 | if (!isValidRecord(i)) { 286 | writeRecNo = i; 287 | break; 288 | } 289 | } 290 | } 291 | 292 | if (writeRecNo == 0) { 293 | writeRecNo = recordCount + 1; 294 | } 295 | 296 | seek(writeRecNo); 297 | writeRecord(data); 298 | 299 | fireModelChangeEvent(new Integer(writeRecNo), data); 300 | } catch (Exception e) { 301 | throw new DuplicateKeyException(UNEXPECTED + e); 302 | } 303 | 304 | return writeRecNo; 305 | } 306 | 307 | /** 308 | * Locks a record so that it can only be updated or deleted 309 | * by this client. 310 | * 311 | * @param recNo The record number. 312 | */ 313 | public synchronized void lock(int recNo) throws RecordNotFoundException { 314 | // do nothing in local mode 315 | } 316 | 317 | /** 318 | * Releases the lock on a record. 319 | * 320 | * @param recNo The record number. 321 | */ 322 | public synchronized void unlock(int recNo) throws RecordNotFoundException { 323 | // do nothing in local mode 324 | } 325 | 326 | /** 327 | * Determines if a record is currenly locked. Returns true if the 328 | * record is locked, false otherwise. 329 | * 330 | * @param recNo The record number. 331 | * @return boolean Return true if record is locked by another user. 332 | */ 333 | public synchronized boolean isLocked(int recNo) throws RecordNotFoundException { 334 | // Always return false in local mode 335 | return false; 336 | } 337 | 338 | /** 339 | * Moves the current database record pointer to the specified record. 340 | * 341 | * @param recno The record number to position the cursor. 342 | * @exception IOException If the record position is invalid. 343 | */ 344 | private synchronized void seek(int recNo) 345 | throws BookingException { 346 | try { 347 | db.seek(headerLen + ((recordLen + 1) * (recNo - 1))); 348 | } catch (Exception e) { 349 | throw new BookingException(UNEXPECTED + e); 350 | } 351 | } 352 | 353 | /** 354 | * Reads a record from the current cursor position of the underlying 355 | * random access file. 356 | * 357 | * @return The array of strings that make up a database record. 358 | * Null value if record is marked deleted. 359 | * @exception BookingException Generated if any unexpected 360 | * exception occur. 361 | */ 362 | private synchronized String[] readRecord() 363 | throws BookingException { 364 | int offset = 1; 365 | String [] rv = null; 366 | byte [] buffer = new byte[recordLen + 1]; 367 | 368 | try { 369 | db.read(buffer); 370 | 371 | if (buffer[0] == LIVE_RECORD) { 372 | rv = new String[fieldCount]; 373 | for (int i = 0; i < fieldCount; i++) { 374 | rv[i] = new String(buffer, offset, fieldInfo[i].getLength()); 375 | offset += fieldInfo[i].getLength(); 376 | } 377 | } else { 378 | rv = null; 379 | } 380 | } catch (Exception e) { 381 | throw new BookingException(UNEXPECTED + e); 382 | } 383 | 384 | return rv; 385 | } 386 | 387 | /** 388 | * Writes a record to the database using the current location of 389 | * the underlying random access file. 390 | * 391 | * @param newData An array of strings in the database specified order. 392 | * @exception BookingException Generated if any unexpected 393 | * exception occur. 394 | */ 395 | private synchronized void writeRecord(String[] newData) 396 | throws BookingException { 397 | if ((newData == null) || (newData.length != fieldCount)) { 398 | throw new BookingException( 399 | "Data: Wrong number of fields in writeRecord() " + 400 | newData.length + " given, " + fieldCount + " required"); 401 | } 402 | 403 | int size, space, toCopy; 404 | byte [] buffer = new byte[recordLen + 1]; 405 | buffer[0] = LIVE_RECORD; 406 | int offset = 1; 407 | 408 | for (int i = 0; i < fieldCount; i++) { 409 | space = fieldInfo[i].getLength(); 410 | String s = rPad(newData[i], space); 411 | byte temp[] = s.getBytes(); 412 | System.arraycopy(temp, 0, buffer, offset, space); 413 | offset += space; 414 | } 415 | 416 | try { 417 | db.write(buffer); 418 | } catch (Exception e) { 419 | throw new BookingException(UNEXPECTED + e); 420 | } 421 | } 422 | 423 | /** 424 | * Pad space to right side of String. 425 | * 426 | * @param s String object. 427 | * @param len The total length of String. 428 | */ 429 | private String rPad(String s, int len) { 430 | String result = s; 431 | if (s.length() < len) { 432 | int spaceLen = len - s.length(); 433 | 434 | for (int i = 0; i < spaceLen; i++) { 435 | result = result + " "; 436 | } 437 | } 438 | 439 | return result; 440 | } 441 | 442 | /** 443 | * Return the record count of the database. 444 | * 445 | * @return The count of record. 446 | * @exception BookingException generated if any unexpected 447 | * exception occur. 448 | */ 449 | public int getRecordCount() throws BookingException { 450 | 451 | long dbFileLen = 0; 452 | int result = 0; 453 | 454 | try { 455 | dbFileLen = db.length(); 456 | } catch (Exception e) { 457 | throw new BookingException(UNEXPECTED + e); 458 | } 459 | 460 | result = (int)((dbFileLen - 70) / (recordLen + 1)); 461 | return result; 462 | } 463 | 464 | /** 465 | * Test the recNo record is valid(not deleted). 466 | * 467 | * @param recNo The record number. 468 | * @return The Boolean value, true mean record is valid, false mean 469 | * record is deleted. 470 | * @exception BookingException generated if any unexpected 471 | * exception occur. 472 | */ 473 | public boolean isValidRecord(int recNo) throws BookingException { 474 | boolean result = false; 475 | 476 | try { 477 | seek(recNo); 478 | byte isValid = db.readByte(); 479 | 480 | result = (isValid == LIVE_RECORD); 481 | } catch (Exception e) { 482 | throw new BookingException(UNEXPECTED + e); 483 | } 484 | 485 | return result; 486 | } 487 | 488 | /** 489 | * Return field count. 490 | * 491 | * @return Field count. 492 | */ 493 | public int getFieldCount() { 494 | return fieldCount; 495 | } 496 | } 497 | -------------------------------------------------------------------------------- /examples/BookingApp/booking/db/DuplicateKeyException.java: -------------------------------------------------------------------------------- 1 | package booking.db; 2 | 3 | /** 4 | * This class defines the database exception used 5 | * in this application to indicate duplicate key 6 | * when append record. 7 | */ 8 | 9 | public class DuplicateKeyException extends BookingException { 10 | /** 11 | * Creates new DuplicateKeyException without detail message. 12 | */ 13 | public DuplicateKeyException() { 14 | super("Duplicate Key."); 15 | } 16 | 17 | /** 18 | * Constructs an DuplicateKeyException with the specified 19 | * detail message. 20 | * 21 | * @param msg the detail message. 22 | */ 23 | public DuplicateKeyException(String msg) { 24 | super(msg); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/BookingApp/booking/db/FieldInfo.java: -------------------------------------------------------------------------------- 1 | package booking.db; 2 | 3 | import java.io.*; 4 | 5 | /** 6 | * This class embodies the name of a field and the maximum width 7 | * that it may have. 8 | */ 9 | public class FieldInfo implements Serializable { 10 | private String name; 11 | private int length; 12 | 13 | /** 14 | * This constructs an initialized FieldInfo object. 15 | * 16 | * @param name - the name of the field. 17 | * @param length - the length of the field. 18 | */ 19 | public FieldInfo(String name, int length) { 20 | this.name = name; 21 | this.length = length; 22 | } 23 | 24 | /** 25 | * This method returns the name of the field. 26 | * 27 | * @return String The name of the field. 28 | */ 29 | public String getName() { 30 | return name; 31 | } 32 | 33 | /** 34 | * This method returns the length of the field. 35 | * 36 | * @return int The length of the field. 37 | */ 38 | public int getLength() { 39 | return length; 40 | } 41 | } -------------------------------------------------------------------------------- /examples/BookingApp/booking/db/LockManager.java: -------------------------------------------------------------------------------- 1 | package booking.db; 2 | 3 | import booking.server.*; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | 9 | /** 10 | * This class eparate concurrent issue in Data class. 11 | */ 12 | public class LockManager { 13 | private final Map lockedRecords = new HashMap(); 14 | 15 | /** 16 | * Locks a record. 17 | * 18 | * @param recNo The record number. 19 | * @param client The client host name. 20 | * @exception InterruptedException Thrown if interrupted occure. 21 | */ 22 | synchronized public void lock(int recNo, Object client) 23 | throws BookingException { 24 | Integer record = new Integer(recNo); 25 | Object oldClient = lockedRecords.get(record); 26 | 27 | System.out.println("Process LockManager lock()"); 28 | 29 | try { 30 | if ((lockedRecords.containsKey(record)) && 31 | (!oldClient.equals(client))) { 32 | throw new BookingException( 33 | "Record is locked by another user, try again later."); 34 | } 35 | 36 | lockedRecords.put(record, client); 37 | } catch(Exception ex) { 38 | throw new BookingException(ex.getMessage()); 39 | } 40 | } 41 | 42 | /** 43 | * Examine record lock by another user. 44 | * 45 | * @param recNo The record number. 46 | * @param client The client host name. 47 | */ 48 | synchronized public boolean isLocked(int recNo, Object client) { 49 | boolean isLocked = false; 50 | Integer record = new Integer(recNo); 51 | Object oldClient = lockedRecords.get(record); 52 | 53 | System.out.println("Process LockManager isLocked()"); 54 | 55 | if(oldClient == null) { 56 | lockedRecords.remove(record); 57 | } else if (!oldClient.equals(client)) { 58 | isLocked = true; 59 | } 60 | 61 | return isLocked; 62 | } 63 | 64 | /** 65 | * Unlocks a record. 66 | * 67 | * @param recNo The record number. 68 | * @param client The client host name. 69 | */ 70 | synchronized public void unlock(int recNo, Object client) { 71 | Integer record = new Integer(recNo); 72 | Object oldClient = lockedRecords.get(record); 73 | 74 | System.out.println("Process LockManager unlock()"); 75 | 76 | if ((oldClient != null) && (oldClient.equals(client))) { 77 | lockedRecords.remove(record); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/BookingApp/booking/db/RecordNotFoundException.java: -------------------------------------------------------------------------------- 1 | package booking.db; 2 | 3 | /** 4 | * This class defines the database exception used 5 | * in this application to indicate can not find 6 | * match record. 7 | */ 8 | 9 | public class RecordNotFoundException extends BookingException { 10 | /** 11 | * Creates new RecordNotFoundException without detail message. 12 | */ 13 | public RecordNotFoundException() { 14 | super("Record not found."); 15 | } 16 | 17 | /** 18 | * Constructs an RecordNotFoundException with the specified 19 | * detail message. 20 | * 21 | * @param msg the detail message. 22 | */ 23 | public RecordNotFoundException(String msg) { 24 | super(msg); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/BookingApp/booking/server/DBRMIServer.java: -------------------------------------------------------------------------------- 1 | package booking.server; 2 | 3 | import booking.db.*; 4 | 5 | import java.net.*; 6 | import java.io.*; 7 | import java.rmi.*; 8 | import java.rmi.registry.*; 9 | import java.rmi.server.*; 10 | 11 | /** 12 | * Provides RMI service for remote client. 13 | */ 14 | public class DBRMIServer { 15 | /** 16 | * The constructor creates the RMI server. 17 | * 18 | * @param dbFile The database file. 19 | * @param remoteHost The rmi server. 20 | * @param rmiPortNumber The rmi port number. 21 | * @param rmiServiceName The rmi service name. 22 | */ 23 | public DBRMIServer(String dbFile, String remoteHost, 24 | String rmiPortNumber, String rmiServiceName) { 25 | try { 26 | Registry myRegistry = 27 | LocateRegistry.createRegistry(Integer.parseInt(rmiPortNumber)); 28 | DBMain dbServer = new DBRMIServerImpl(dbFile); 29 | String urlString = "rmi://" + remoteHost + ":" + rmiPortNumber + 30 | "/" + rmiServiceName; 31 | myRegistry.rebind(rmiServiceName, dbServer); 32 | System.out.println("Server started, waiting for client requests."); 33 | } catch(Exception ex) { 34 | System.out.println(ex); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/BookingApp/booking/server/DBRMIServerImpl.java: -------------------------------------------------------------------------------- 1 | package booking.server; 2 | 3 | import booking.db.*; 4 | import booking.client.*; 5 | 6 | import java.rmi.*; 7 | import java.rmi.server.*; 8 | 9 | /** 10 | * Implemention of RMI, Data local methods are wrapped with 11 | * remote methods for remote client. 12 | */ 13 | public class DBRMIServerImpl 14 | extends UnicastRemoteObject implements DBMain { 15 | 16 | private final static LockManager LOCK_MANAGER = new LockManager(); 17 | private static Data data; 18 | private static final String UNEXPECTED = 19 | "DBRMIServerImpl - Unexpected database access problem: "; 20 | 21 | /** 22 | * The constructor creates the database instance. 23 | * 24 | * @param dbname The database file path & name 25 | * @exception BookingException Thrown if any error occur. 26 | * @exception RemoteException Thrown if remote error occur. 27 | */ 28 | public DBRMIServerImpl(String dbname) 29 | throws RemoteException, BookingException { 30 | 31 | super(); 32 | data = new Data(dbname); 33 | } 34 | 35 | /** 36 | * Gets a requested record from the database based on record number. 37 | * 38 | * @param recNo The number of the record to read (first record is 1). 39 | * @return String array for the record or null if the record has been 40 | * marked for deletion. 41 | * @exception RecordNotFoundException Thrown if database file cannot 42 | * be accessed. 43 | * @exception RemoteException Thrown if remote error occur. 44 | */ 45 | public String [] read(int recNo) 46 | throws RecordNotFoundException, RemoteException { 47 | return data.read(recNo); 48 | } 49 | 50 | /** 51 | * Modifies the fields of a record. 52 | * 53 | * @param recNo The number of the record. 54 | * @param data The new value, field n appears in data[n] 55 | * @exception RecordNotFoundException Thrown if database file cannot 56 | * be accessed. 57 | * @exception RemoteException Thrown if remote error occur. 58 | */ 59 | public void update(int recNo, String [] data) 60 | throws RecordNotFoundException, RemoteException { 61 | 62 | try { 63 | if (isLocked(recNo)) { 64 | throw new RemoteException( 65 | "Record is locked by another user, try again later."); 66 | } else { 67 | lock(recNo); 68 | this.data.update(recNo, data); 69 | unlock(recNo); 70 | } 71 | } catch (Exception ex) { 72 | throw new RemoteException(ex.getMessage()); 73 | } 74 | } 75 | 76 | /** 77 | * Deletes a record, making the record number and associated disk 78 | * storage available for reuse. 79 | * 80 | * @param recNo The number of the record. 81 | * @exception RecordNotFoundException Thrown if database file cannot 82 | * be accessed. 83 | * @exception RemoteException Thrown if remote error occur. 84 | */ 85 | public void delete(int recNo) 86 | throws RecordNotFoundException, RemoteException { 87 | 88 | try { 89 | if (isLocked(recNo)) { 90 | throw new RemoteException( 91 | "Record is locked by another user, try again later."); 92 | } else { 93 | lock(recNo); 94 | this.data.delete(recNo); 95 | unlock(recNo); 96 | } 97 | } catch (Exception ex) { 98 | throw new RemoteException(ex.getMessage()); 99 | } 100 | } 101 | 102 | /** 103 | * This method searches the database for match the specified 104 | * criteria. 105 | * 106 | * @param criteria A null value in criteria[n] matches any field 107 | * value. A non-null value in criteria[n] matches any field 108 | * value that begins with criteria[n]. 109 | * @return int array The matching record number. 110 | * @exception RecordNotFoundException Thrown when can not find 111 | * any match record. 112 | * @exception RemoteException Thrown if remote error occur. 113 | */ 114 | public int [] find(String [] criteria) 115 | throws RecordNotFoundException, RemoteException { 116 | return data.find(criteria); 117 | } 118 | 119 | /** 120 | * Creates a new record in the database (possibly reusing a 121 | * deleted entry) 122 | * 123 | * @param data The value of the record. 124 | * @return int The record number of the new record. 125 | * @exception DuplicateKeyException thrown if duplicate key occure. 126 | * @exception RemoteException Thrown if remote error occur. 127 | */ 128 | public int create(String [] data) 129 | throws DuplicateKeyException, RemoteException { 130 | return this.data.create(data); 131 | } 132 | 133 | /** 134 | * Locks a record so that it can only be updated or deleted 135 | * by this client. 136 | * 137 | * @param recNo The record number. 138 | * @exception RecordNotFoundException Thrown if any error occur. 139 | * @exception RemoteException Thrown if remote error occur. 140 | */ 141 | public void lock(int recNo) 142 | throws RecordNotFoundException, RemoteException { 143 | 144 | try { 145 | LOCK_MANAGER.lock(recNo, getClientHost()); 146 | } catch (Exception ex) { 147 | throw new RemoteException(ex.getMessage()); 148 | } 149 | } 150 | 151 | /** 152 | * Releases the lock on a record. 153 | * 154 | * @param recNo The record number. 155 | * @exception RecordNotFoundException Thrown if any error occur. 156 | * @exception RemoteException Thrown if remote error occur. 157 | */ 158 | public void unlock(int recNo) 159 | throws RecordNotFoundException, RemoteException { 160 | 161 | try { 162 | LOCK_MANAGER.unlock(recNo, getClientHost()); 163 | } catch (Exception ex) { 164 | throw new RemoteException(ex.getMessage()); 165 | } 166 | } 167 | 168 | /** 169 | * Determines if a record is currenly locked. Returns true if the 170 | * record is locked, false otherwise. 171 | * 172 | * @param recNo The record number. 173 | * @return boolean Return true if record is locked by another user. 174 | * @exception RecordNotFoundException Thrown if any error occur. 175 | * @exception RemoteException Thrown if remote error occur. 176 | */ 177 | public boolean isLocked(int recNo) 178 | throws RecordNotFoundException, RemoteException { 179 | 180 | boolean result = false; 181 | try { 182 | result = LOCK_MANAGER.isLocked(recNo, getClientHost()); 183 | } catch (Exception ex) { 184 | throw new RemoteException(ex.getMessage()); 185 | } 186 | 187 | return result; 188 | } 189 | 190 | /** 191 | * Booking model state change listener registration methods. 192 | * 193 | * @param sv The suncertify view object. 194 | * @exception BookingException Thrown if MVC error occur. 195 | * @exception RemoteException Thrown if remote error occur. 196 | */ 197 | public void addChangeListener(BookingView bv) 198 | throws BookingException, RemoteException { 199 | data.addChangeListener(bv); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /examples/CalculatorApp/Calculator.java: -------------------------------------------------------------------------------- 1 | public class Calculator { 2 | private static final char NO_OP = '\0'; 3 | private static final char PLUS = '+'; 4 | private static final char SUBTRACT = '-'; 5 | private static final char MULTIPLY = '*'; 6 | private static final char DIVIDE = '/'; 7 | 8 | private float number1 = 0.0F; 9 | private char operator = NO_OP; 10 | 11 | public String opEquals(String number) { 12 | float result; 13 | result = performOperation(parseNumber(number)); 14 | operator = NO_OP; 15 | return Float.toString((number1 = result)); 16 | } 17 | 18 | public String opAdd(String number) { 19 | float result; 20 | 21 | result = performOperation(parseNumber(number)); 22 | operator = PLUS; 23 | return Float.toString((number1 = result)); 24 | } 25 | 26 | public String opSubtract(String number) { 27 | float result; 28 | 29 | result = performOperation(parseNumber(number)); 30 | operator = SUBTRACT; 31 | return Float.toString((number1 = result)); 32 | } 33 | 34 | public String opMultiply(String number) { 35 | float result; 36 | 37 | result = performOperation(parseNumber(number)); 38 | operator = MULTIPLY; 39 | return Float.toString((number1 = result)); 40 | } 41 | 42 | public String opDivide(String number) { 43 | float result; 44 | 45 | result = performOperation(parseNumber(number)); 46 | operator = DIVIDE; 47 | return Float.toString((number1 = result)); 48 | } 49 | 50 | private float performOperation(float number2) { 51 | float result = 0.0F; 52 | 53 | switch (operator) { 54 | case NO_OP: 55 | result = number2; 56 | break; 57 | case PLUS: 58 | result = number1 + number2; 59 | break; 60 | case SUBTRACT: 61 | result = number1 - number2; 62 | break; 63 | case MULTIPLY: 64 | result = number1 * number2; 65 | break; 66 | case DIVIDE: 67 | result = number1 / number2; 68 | break; 69 | } 70 | 71 | return result; 72 | } 73 | 74 | protected static float parseNumber(String number) { 75 | float real_number; 76 | 77 | try { 78 | real_number = Float.parseFloat(number); 79 | } catch (NumberFormatException e) { 80 | real_number = Float.NaN; 81 | } 82 | 83 | return real_number; 84 | } 85 | } -------------------------------------------------------------------------------- /examples/CalculatorApp/CalculatorGUI.java: -------------------------------------------------------------------------------- 1 | import java.awt.*; 2 | import java.awt.event.*; 3 | import javax.swing.*; 4 | 5 | public class CalculatorGUI { 6 | private JButton btn0, btn1, btn2, btn3, btn4; 7 | private JButton btn5, btn6, btn7, btn8, btn9; 8 | private JButton btnEqual, btnPlus, btnMinus; 9 | private JButton btnPeriod, btnMult, btnDiv; 10 | private JPanel buttonPane; 11 | private JPanel calculatorPane; 12 | private SwingScreen screen; 13 | private Calculator calculator; 14 | private boolean isReady; 15 | 16 | public CalculatorGUI() { 17 | calculator = new Calculator(); 18 | isReady = true; 19 | screen = new CalculatorScreen("0.0", JLabel.RIGHT); 20 | btn0 = new JButton("0"); 21 | btn1 = new JButton("1"); 22 | btn2 = new JButton("2"); 23 | btn3 = new JButton("3"); 24 | btn4 = new JButton("4"); 25 | btn5 = new JButton("5"); 26 | btn6 = new JButton("6"); 27 | btn7 = new JButton("7"); 28 | btn8 = new JButton("8"); 29 | btn9 = new JButton("9"); 30 | btnEqual = new JButton("="); 31 | btnPlus = new JButton("+"); 32 | btnMinus = new JButton("-"); 33 | btnMult = new JButton("*"); 34 | btnDiv = new JButton("/"); 35 | btnPeriod = new JButton("."); 36 | buttonPane = new JPanel(); 37 | calculatorPane = new JPanel(); 38 | } 39 | 40 | public JPanel getCalculatorPane() { 41 | buttonPane.setLayout(new GridLayout(4, 4)); 42 | 43 | buttonPane.add(btn7); 44 | buttonPane.add(btn8); 45 | buttonPane.add(btn9); 46 | buttonPane.add(btnDiv); 47 | buttonPane.add(btn4); 48 | buttonPane.add(btn5); 49 | buttonPane.add(btn6); 50 | buttonPane.add(btnMult); 51 | buttonPane.add(btn1); 52 | buttonPane.add(btn2); 53 | buttonPane.add(btn3); 54 | buttonPane.add(btnMinus); 55 | buttonPane.add(btn0); 56 | buttonPane.add(btnPeriod); 57 | buttonPane.add(btnEqual); 58 | buttonPane.add(btnPlus); 59 | 60 | OperationHanlder operationHanlder = new OperationHanlder(); 61 | NonOperationHanlder nonOperationHanlder = new NonOperationHanlder(); 62 | 63 | btn0.addActionListener(nonOperationHanlder); 64 | btn1.addActionListener(nonOperationHanlder); 65 | btn2.addActionListener(nonOperationHanlder); 66 | btn3.addActionListener(nonOperationHanlder); 67 | btn4.addActionListener(nonOperationHanlder); 68 | btn5.addActionListener(nonOperationHanlder); 69 | btn6.addActionListener(nonOperationHanlder); 70 | btn7.addActionListener(nonOperationHanlder); 71 | btn8.addActionListener(nonOperationHanlder); 72 | btn9.addActionListener(nonOperationHanlder); 73 | btnPeriod.addActionListener(nonOperationHanlder); 74 | btnPlus.addActionListener(operationHanlder); 75 | btnMinus.addActionListener(operationHanlder); 76 | btnMult.addActionListener(operationHanlder); 77 | btnDiv.addActionListener(operationHanlder); 78 | btnEqual.addActionListener(operationHanlder); 79 | 80 | calculatorPane.setLayout(new BorderLayout()); 81 | calculatorPane.add(screen, BorderLayout.NORTH); 82 | calculatorPane.add(buttonPane, BorderLayout.CENTER); 83 | 84 | return calculatorPane; 85 | } 86 | 87 | private class OperationHanlder implements ActionListener { 88 | public void actionPerformed(ActionEvent event) { 89 | char operator = event.getActionCommand().charAt(0); 90 | String result = ""; 91 | switch (operator) { 92 | case '+': 93 | result = calculator.opAdd(screen.getScreen()); 94 | break; 95 | case '-': 96 | result = calculator.opSubtract(screen.getScreen()); 97 | break; 98 | case '*': 99 | result = calculator.opMultiply(screen.getScreen()); 100 | break; 101 | case '/': 102 | result = calculator.opDivide(screen.getScreen()); 103 | break; 104 | case '=': 105 | result = calculator.opEquals(screen.getScreen()); 106 | break; 107 | } 108 | screen.display(result); 109 | isReady = true; 110 | } 111 | } 112 | 113 | private class NonOperationHanlder implements ActionListener { 114 | public void actionPerformed(ActionEvent ae) { 115 | if (isReady) { 116 | screen.display(ae.getActionCommand()); 117 | isReady = false; 118 | } else { 119 | screen.display(screen.getScreen() + 120 | ae.getActionCommand().charAt(0)); 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /examples/CalculatorApp/CalculatorScreen.java: -------------------------------------------------------------------------------- 1 | public class CalculatorScreen extends SwingScreen { 2 | public CalculatorScreen(String s) { 3 | super(s); 4 | } 5 | 6 | public CalculatorScreen(String s, int align) { 7 | super(s, align); 8 | } 9 | 10 | public void display(String s) { 11 | setText(s); 12 | } 13 | 14 | public String getScreen() { 15 | return getText(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/CalculatorApp/MyCalculator.java: -------------------------------------------------------------------------------- 1 | import java.awt.*; 2 | import javax.swing.*; 3 | 4 | public class MyCalculator { 5 | public static void main(String args[]) { 6 | CalculatorGUI cg = new CalculatorGUI(); 7 | JFrame frame = new JFrame("Calculator"); 8 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 9 | frame.setSize(250, 250); 10 | frame.getContentPane().add( 11 | cg.getCalculatorPane(), BorderLayout.CENTER); 12 | frame.setVisible (true); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/CalculatorApp/Screen.java: -------------------------------------------------------------------------------- 1 | public interface Screen { 2 | public void display(String s); 3 | public String getScreen(); 4 | } 5 | -------------------------------------------------------------------------------- /examples/CalculatorApp/SwingScreen.java: -------------------------------------------------------------------------------- 1 | import javax.swing.*; 2 | 3 | public abstract class SwingScreen extends JLabel implements Screen { 4 | public SwingScreen(String s) { 5 | super(s); 6 | } 7 | 8 | public SwingScreen(String s, int align) { 9 | super(s, align); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/ChatApp/ChatClient.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.net.*; 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.awt.event.*; 6 | 7 | public class ChatClient { 8 | private JFrame frame; 9 | private JPanel panel; 10 | private JTextArea incoming; 11 | private JTextField outGoing; 12 | private JTextField nickName; 13 | private JButton sendButton; 14 | private JScrollPane scroll; 15 | private BufferedReader reader; 16 | private PrintWriter writer; 17 | private Socket sock; 18 | private String remoteHost = "localhost"; 19 | private int portNumber = 8000; 20 | 21 | public static void main(String[] args) { 22 | new ChatClient().go(); 23 | } 24 | 25 | private void go() { 26 | getConnection(); 27 | IncomingReader incomingReader = new IncomingReader(); 28 | new Thread(incomingReader).start(); 29 | constructGUI(); 30 | } 31 | 32 | private void getConnection() { 33 | try { 34 | sock = new Socket(remoteHost, portNumber); 35 | reader = new BufferedReader( 36 | new InputStreamReader(sock.getInputStream())); 37 | writer = new PrintWriter(sock.getOutputStream()); 38 | } catch (ConnectException ce) { 39 | System.out.println("Remote server is not ready."); 40 | System.exit(0); 41 | } catch (Exception e) { 42 | e.printStackTrace(); 43 | System.exit(0); 44 | } 45 | } 46 | 47 | private void constructGUI() { 48 | frame = new JFrame("Chat client"); 49 | panel = new JPanel(); 50 | incoming = new JTextArea(15, 50); 51 | incoming.setLineWrap(true); 52 | incoming.setWrapStyleWord(true); 53 | incoming.setEditable(false); 54 | scroll = new JScrollPane(incoming, 55 | ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, 56 | ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 57 | outGoing = new JTextField(20); 58 | nickName = new JTextField("default", 10); 59 | sendButton = new JButton("Send"); 60 | sendButton.addActionListener(new SendButtonListener()); 61 | outGoing.addKeyListener(new TextFieldListener()); 62 | panel.add(scroll); 63 | panel.add(new JLabel("Nick:")); 64 | panel.add(nickName); 65 | panel.add(outGoing); 66 | panel.add(sendButton); 67 | frame.getContentPane().add(BorderLayout.CENTER, panel); 68 | frame.setSize(600, 400); 69 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 70 | frame.setVisible(true); 71 | } 72 | 73 | private class SendButtonListener implements ActionListener { 74 | public void actionPerformed(ActionEvent ae) { 75 | sendMessage(nickName.getText() + ": " + 76 | outGoing.getText()); 77 | } 78 | } 79 | 80 | private void appendMessage(String message) { 81 | incoming.append(message); 82 | } 83 | 84 | private class TextFieldListener implements KeyListener { 85 | public void keyPressed(KeyEvent e) { } 86 | public void keyReleased(KeyEvent e) { } 87 | 88 | public void keyTyped(KeyEvent e) { 89 | if (e.getKeyChar() == '\n') { 90 | sendMessage(nickName.getText() + ": " + 91 | outGoing.getText()); 92 | } 93 | } 94 | } 95 | 96 | private void sendMessage(String message) { 97 | try { 98 | writer.println(message); 99 | writer.flush(); 100 | } catch (Exception e) { 101 | e.printStackTrace(); 102 | } 103 | outGoing.setText(""); 104 | outGoing.requestFocus(); 105 | } 106 | 107 | private class IncomingReader implements Runnable { 108 | public void run() { 109 | String message; 110 | try { 111 | while ((message = reader.readLine()) != null) { 112 | appendMessage(message + "\n"); 113 | } 114 | } catch (Exception e) { 115 | e.printStackTrace(); 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /examples/ChatApp/ChatServer.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.net.*; 3 | import java.util.*; 4 | import javax.swing.*; 5 | import java.awt.*; 6 | 7 | public class ChatServer { 8 | private JFrame frame; 9 | private JPanel panel; 10 | private JTextArea messageLog; 11 | private JScrollPane scroll; 12 | 13 | private ArrayList clients; 14 | private ServerSocket serverSocket; 15 | 16 | private int portNumber = 8000; 17 | private int userCount = 0; 18 | 19 | public static void main(String[] args) { 20 | new ChatServer().go(); 21 | } 22 | 23 | public void go() { 24 | constructGUI(); 25 | clients = new ArrayList(); 26 | 27 | try { 28 | serverSocket = new ServerSocket(portNumber); 29 | 30 | while (true) { 31 | Socket clientSocket = serverSocket.accept(); 32 | messageLog.append("Client " + (++userCount) + " add in.\n"); 33 | PrintWriter writer = 34 | new PrintWriter(clientSocket.getOutputStream()); 35 | clients.add(writer); 36 | ClientHandler clientHandler = new ClientHandler(clientSocket); 37 | new Thread(clientHandler).start(); 38 | } 39 | } catch (Exception e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | private void constructGUI() { 45 | frame = new JFrame("Chat server"); 46 | panel = new JPanel(); 47 | messageLog = new JTextArea(6, 20); 48 | messageLog.setLineWrap(true); 49 | messageLog.setWrapStyleWord(true); 50 | messageLog.setEditable(false); 51 | scroll = new JScrollPane(messageLog, 52 | ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, 53 | ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 54 | panel.add(BorderLayout.CENTER, scroll); 55 | frame.getContentPane().add(BorderLayout.CENTER, panel); 56 | frame.setSize(300, 180); 57 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 58 | frame.setVisible(true); 59 | } 60 | 61 | private void tellEveryClient(String message) throws IOException { 62 | Iterator i = clients.iterator(); 63 | while (i.hasNext()) { 64 | PrintWriter printWriter = (PrintWriter)i.next(); 65 | printWriter.println(message); 66 | printWriter.flush(); 67 | } 68 | } 69 | 70 | private class ClientHandler implements Runnable { 71 | private BufferedReader reader; 72 | private Socket socket; 73 | 74 | public ClientHandler(Socket clientSocket) { 75 | try { 76 | socket = clientSocket; 77 | InputStreamReader inputStreamReader = 78 | new InputStreamReader(socket.getInputStream()); 79 | reader = new BufferedReader(inputStreamReader); 80 | } catch (Exception e) { 81 | e.printStackTrace(); 82 | } 83 | } 84 | 85 | public void run() { 86 | String message; 87 | 88 | try { 89 | while ((message = reader.readLine()) != null) { 90 | tellEveryClient(message); 91 | } 92 | } catch (Exception e) { 93 | e.printStackTrace(); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /examples/Others/Course.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class Course { 4 | private String name; 5 | private Teacher teacher; 6 | private Set students; 7 | 8 | public String getName() { 9 | return name; 10 | } 11 | 12 | public Teacher getTeacher() { 13 | return teacher; 14 | } 15 | 16 | public Set getStudents() { 17 | return students; 18 | } 19 | 20 | public void setName(String name) { 21 | this.name = name; 22 | } 23 | 24 | public void setTeacher(Teacher teacher) { 25 | this.teacher = teacher; 26 | } 27 | 28 | public void setStudents(Set students) { 29 | this.students = students; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/Others/MyMap.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | import java.util.ArrayList; 3 | 4 | public class MyMap { 5 | private List keyList = new ArrayList(); 6 | private List valueList = new ArrayList(); 7 | 8 | public void add(Object key, Object value) { 9 | if (keyList.size() == 0 || !keyList.contains(key)) { 10 | keyList.add(key); 11 | valueList.add(value); 12 | } 13 | } 14 | 15 | public Object get(Object key) { 16 | Object result; 17 | int index = 0; 18 | 19 | if ((index = keyList.indexOf(key)) != -1) { 20 | result = valueList.get(index); 21 | } else { 22 | result = null; 23 | } 24 | 25 | return result; 26 | } 27 | 28 | public Object remove(Object key) { 29 | Object result; 30 | int index = 0; 31 | 32 | if ((index = keyList.indexOf(key)) != -1) { 33 | keyList.remove(index); 34 | result = valueList.remove(index); 35 | } else { 36 | result = null; 37 | } 38 | 39 | return result; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/Others/NineNine.java: -------------------------------------------------------------------------------- 1 | public class NineNine { 2 | public static void main(String args[]) { 3 | int i = 1; 4 | while (i <= 9) { 5 | int j = 1; 6 | 7 | while (j <= 9) { 8 | System.out.println(i + "*" + j + "=" + (i * j)); 9 | j++; 10 | } 11 | 12 | System.out.println(); 13 | i++; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/Others/ObjectCount.java: -------------------------------------------------------------------------------- 1 | public class ObjectCount { 2 | private int count = 0; 3 | private static int objectSerial = 0; 4 | 5 | public ObjectCount() { 6 | objectSerial++; 7 | count = objectSerial; 8 | } 9 | 10 | public String toString() { 11 | return "ObjectCount: " + count; 12 | } 13 | 14 | public static void main(String args[]) { 15 | System.out.println(new ObjectCount()); 16 | System.out.println(new ObjectCount()); 17 | System.out.println(new ObjectCount()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/Others/Student.java: -------------------------------------------------------------------------------- 1 | public class Student { 2 | private String name; 3 | private char gender; 4 | 5 | public String getName() { 6 | return name; 7 | } 8 | 9 | public char getGender() { 10 | return gender; 11 | } 12 | 13 | public void setName(String name) { 14 | this.name = name; 15 | } 16 | 17 | public void setGender(char gender) { 18 | this.gender = gender; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/Others/Teacher.java: -------------------------------------------------------------------------------- 1 | public class Teacher { 2 | private String name; 3 | private char gender; 4 | private boolean isMarried; 5 | 6 | public String getName() { 7 | return name; 8 | } 9 | 10 | public char getGender() { 11 | return gender; 12 | } 13 | 14 | public boolean getIsMarried() { 15 | return isMarried; 16 | } 17 | 18 | public void setName(String name) { 19 | this.name = name; 20 | } 21 | 22 | public void setGender(char gender) { 23 | this.gender = gender; 24 | } 25 | 26 | public void setIsMarried(boolean isMarried) { 27 | this.isMarried = isMarried; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/Others/TestMyMap.java: -------------------------------------------------------------------------------- 1 | public class TestMyMap { 2 | public static void main(String args[]) { 3 | MyMap mm = new MyMap(); 4 | 5 | mm.add("1", "Apple"); 6 | mm.add("2", "Banana"); 7 | mm.add("3", "Watermelon"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/ThermosApp/CoolWaterContainer.java: -------------------------------------------------------------------------------- 1 | public class CoolWaterContainer extends WaterContainer { 2 | public CoolWaterContainer(int capacity) { 3 | super(capacity); 4 | } 5 | 6 | public int getTemperature() { 7 | return 28; 8 | } 9 | 10 | public void reBrew() { 11 | // Do nothing 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/ThermosApp/Heater.java: -------------------------------------------------------------------------------- 1 | public class Heater { 2 | public static int brew(int water) { 3 | try { 4 | Thread.sleep(100); 5 | } catch (Exception ex) { } 6 | return water; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/ThermosApp/HotWaterContainer.java: -------------------------------------------------------------------------------- 1 | public class HotWaterContainer extends WaterContainer { 2 | private int temperature; 3 | static final int MIN_TEMPERATURE = 80; 4 | static final int MAX_TEMPERATURE = 100; 5 | 6 | public HotWaterContainer(int capacity) { 7 | super(capacity); 8 | temperature = MAX_TEMPERATURE; 9 | new Thread(new DropTemperature()).start(); 10 | } 11 | 12 | public int getTemperature() { 13 | return temperature; 14 | } 15 | 16 | public void reBrew() { 17 | new Thread(new ReBrew()).start(); 18 | } 19 | 20 | public synchronized void addWater(int water) { 21 | temperature = averageTemp(super.getCapacity(), temperature, 22 | water, 100); 23 | super.addWater(water); 24 | } 25 | 26 | private int averageTemp(int oldCap, int oldTemp, 27 | int newCap, int newTemp) { 28 | int result = 0; 29 | result = ((oldCap * oldTemp) + (newCap * newTemp)) 30 | / (oldCap + newCap); 31 | return result; 32 | } 33 | 34 | public class ReBrew implements Runnable { 35 | public void run() { 36 | setIsReady(false); 37 | setIsBrewing(true); 38 | 39 | for (; temperature < MAX_TEMPERATURE; ) { 40 | try { 41 | Thread.sleep(100); 42 | temperature++; 43 | } catch (Exception ex) { 44 | // 45 | } 46 | } 47 | 48 | setIsReady(true); 49 | setIsBrewing(false); 50 | } 51 | } 52 | 53 | public class DropTemperature implements Runnable { 54 | public void run() { 55 | while (true) { 56 | try { 57 | Thread.sleep(1000); 58 | temperature--; 59 | } catch (Exception ex) { 60 | // 61 | } 62 | 63 | if (temperature < MIN_TEMPERATURE) { 64 | reBrew(); 65 | } 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /examples/ThermosApp/TestThermos.java: -------------------------------------------------------------------------------- 1 | public class TestThermos { 2 | public static void main(String[] args) { 3 | HotWaterContainer h = new HotWaterContainer(2); 4 | CoolWaterContainer c = new CoolWaterContainer(50); 5 | ThermosGui g = new ThermosGui(); 6 | Thermos t = new Thermos(h, c, g); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/ThermosApp/Thermos.java: -------------------------------------------------------------------------------- 1 | import java.awt.event.*; 2 | 3 | public class Thermos { 4 | private WaterContainer hot; 5 | private WaterContainer cool; 6 | private ThermosGui gui; 7 | 8 | public Thermos(WaterContainer hot, 9 | WaterContainer cool, 10 | ThermosGui gui) { 11 | this.hot = hot; 12 | this.cool = cool; 13 | this.gui = gui; 14 | 15 | gui.addListener(new ActionListener[] { 16 | new AddCoolWaterListener(), 17 | new ReBrewListener(), 18 | new CoolToHotListener(), 19 | new UseHotWaterListener() 20 | }); 21 | 22 | new Thread(new RefreshInfoPanel()).start(); 23 | } 24 | 25 | public void addCoolWater() { 26 | cool.addWater(CoolWaterContainer.MAX_CAPACITY); 27 | } 28 | 29 | public void coolToHot() { 30 | new Thread(new CoolToHot()).start(); 31 | } 32 | 33 | public class CoolToHot implements Runnable { 34 | public void run() { 35 | cool.setIsHeating(true); 36 | while (cool.isReady() && !hot.isFull()) { 37 | int water = cool.useWater(1); 38 | hot.addWater(Heater.brew(water)); 39 | } 40 | cool.setIsHeating(false); 41 | } 42 | } 43 | 44 | public class RefreshInfoPanel implements Runnable { 45 | public void run() { 46 | boolean status[] = new boolean[4]; 47 | 48 | while (true) { 49 | try { 50 | Thread.sleep(200); 51 | } catch (Exception ex) { 52 | 53 | } 54 | gui.showInformation(hot.getCapacity(), 55 | cool.getCapacity(), 56 | hot.getTemperature()); 57 | 58 | status[0] = hot.lowCapacity(); 59 | status[1] = cool.lowCapacity(); 60 | status[2] = hot.isBrewing(); 61 | status[3] = cool.isHeating(); 62 | gui.showStatus(status); 63 | } 64 | } 65 | } 66 | 67 | public class AddCoolWaterListener implements ActionListener { 68 | public void actionPerformed(ActionEvent ae) { 69 | addCoolWater(); 70 | } 71 | } 72 | 73 | public class ReBrewListener implements ActionListener { 74 | public void actionPerformed(ActionEvent ae) { 75 | hot.reBrew(); 76 | } 77 | } 78 | 79 | public class CoolToHotListener implements ActionListener { 80 | public void actionPerformed(ActionEvent ae) { 81 | coolToHot(); 82 | } 83 | } 84 | 85 | public class UseHotWaterListener implements ActionListener { 86 | public void actionPerformed(ActionEvent ae) { 87 | hot.useWater(1); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /examples/ThermosApp/ThermosGui.java: -------------------------------------------------------------------------------- 1 | import javax.swing.*; 2 | import java.awt.*; 3 | import java.awt.event.*; 4 | 5 | public class ThermosGui { 6 | private JFrame frame; 7 | private Container container; 8 | private JPanel infoPanel, btnPanel, statusPanel; 9 | private JLabel hot, cool, capacity, temperature; 10 | private JTextField hotCapacity, coolCapacity, hotTemperature; 11 | private JButton addCoolWater, reBrew, coolToHot, useHotWater; 12 | private JCheckBox lowHot, lowCool, brewing, heating; 13 | 14 | public ThermosGui() { 15 | buildGui(); 16 | } 17 | 18 | private void buildGui() { 19 | frame = new JFrame("Java熱水瓶"); 20 | statusPanel = new JPanel(); 21 | lowHot = new JCheckBox("熱水太少了"); 22 | lowCool = new JCheckBox("冷水太少了"); 23 | brewing = new JCheckBox("煮沸中..."); 24 | heating = new JCheckBox("冷水加到熱水中..."); 25 | statusPanel.setLayout(new FlowLayout()); 26 | statusPanel.add(lowHot); 27 | statusPanel.add(lowCool); 28 | statusPanel.add(brewing); 29 | statusPanel.add(heating); 30 | 31 | infoPanel = new JPanel(); 32 | hot = new JLabel("熱"); 33 | cool = new JLabel("冷"); 34 | capacity = new JLabel("容量"); 35 | temperature = new JLabel("溫度"); 36 | hotCapacity = new JTextField("0", 10); 37 | coolCapacity = new JTextField("0", 10); 38 | hotTemperature = new JTextField("0", 10); 39 | infoPanel.setLayout(new GridLayout(3, 3)); 40 | infoPanel.add(new JLabel("")); 41 | infoPanel.add(hot); 42 | infoPanel.add(cool); 43 | infoPanel.add(capacity); 44 | infoPanel.add(hotCapacity); 45 | infoPanel.add(coolCapacity); 46 | infoPanel.add(temperature); 47 | infoPanel.add(hotTemperature); 48 | infoPanel.add(new JLabel("")); 49 | 50 | btnPanel = new JPanel(); 51 | addCoolWater = new JButton("加冷水"); 52 | reBrew = new JButton("再沸騰"); 53 | coolToHot = new JButton("冷水加到熱水"); 54 | useHotWater = new JButton("使用熱水"); 55 | btnPanel.setLayout(new FlowLayout()); 56 | btnPanel.add(addCoolWater); 57 | btnPanel.add(reBrew); 58 | btnPanel.add(coolToHot); 59 | btnPanel.add(useHotWater); 60 | 61 | container = frame.getContentPane(); 62 | container.add(statusPanel, BorderLayout.NORTH); 63 | container.add(infoPanel, BorderLayout.CENTER); 64 | container.add(btnPanel, BorderLayout.SOUTH); 65 | 66 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 67 | frame.pack(); 68 | frame.setVisible(true); 69 | } 70 | 71 | public void showInformation(int hotCapacity, int coolCapacity, 72 | int hotTemperature) { 73 | this.hotCapacity.setText(Integer.toString(hotCapacity)); 74 | this.coolCapacity.setText(Integer.toString(coolCapacity)); 75 | this.hotTemperature.setText(Integer.toString(hotTemperature)); 76 | } 77 | 78 | public void showStatus(boolean status[]) { 79 | lowHot.setSelected(status[0]); 80 | lowCool.setSelected(status[1]); 81 | brewing.setSelected(status[2]); 82 | heating.setSelected(status[3]); 83 | } 84 | 85 | public void addListener(ActionListener a[]) { 86 | addCoolWater.addActionListener(a[0]); 87 | reBrew.addActionListener(a[1]); 88 | coolToHot.addActionListener(a[2]); 89 | useHotWater.addActionListener(a[3]); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /examples/ThermosApp/WaterContainer.java: -------------------------------------------------------------------------------- 1 | public abstract class WaterContainer { 2 | private int capacity; 3 | private boolean isReady; 4 | private boolean isBrewing; 5 | private boolean isHeating; 6 | static final int MAX_CAPACITY = 50; 7 | static final int MIN_CAPACITY = 10; 8 | 9 | public WaterContainer(int capacity) { 10 | if (capacity <= MAX_CAPACITY) { 11 | this.capacity = capacity; 12 | } else { 13 | this.capacity = MAX_CAPACITY; 14 | } 15 | 16 | isReady = true; 17 | isBrewing = false; 18 | isHeating = false; 19 | } 20 | 21 | public int getCapacity() { 22 | return capacity; 23 | } 24 | 25 | public boolean isFull() { 26 | return (capacity == MAX_CAPACITY); 27 | } 28 | 29 | public boolean lowCapacity() { 30 | return (capacity < MIN_CAPACITY); 31 | } 32 | 33 | public synchronized void addWater(int water) { 34 | if ((water + capacity) < MAX_CAPACITY) { 35 | capacity += water; 36 | } else { 37 | capacity = MAX_CAPACITY; 38 | } 39 | } 40 | 41 | public boolean isReady() { 42 | return isReady; 43 | } 44 | 45 | public void setIsReady(boolean isReady) { 46 | this.isReady = isReady; 47 | } 48 | 49 | public boolean isBrewing() { 50 | return isBrewing; 51 | } 52 | 53 | public void setIsBrewing(boolean isBrewing) { 54 | this.isBrewing = isBrewing; 55 | } 56 | 57 | public boolean isHeating() { 58 | return isHeating; 59 | } 60 | 61 | public void setIsHeating(boolean isHeating) { 62 | this.isHeating = isHeating; 63 | } 64 | 65 | public synchronized int useWater(int water) { 66 | if (capacity >= water) { 67 | capacity -= water; 68 | return water; 69 | } else { 70 | isReady = false; 71 | return 0; 72 | } 73 | } 74 | 75 | public abstract int getTemperature(); 76 | public abstract void reBrew(); 77 | } 78 | --------------------------------------------------------------------------------