Wednesday, October 14, 2009

Selecting R'EPOSITORIES'



[ Team LiB ]





Selecting REPOSITORIES


There are five ENTITIES in the design that are roots of AGGREGATES, so we can limit our consideration to these, since none of the other objects is allowed to have REPOSITORIES.


To decide which of these candidates should actually have a REPOSITORY, we must go back to the application requirements. In order to take a booking through the Booking Application, the user needs to select the Customer(s) playing the various roles (shipper, receiver, and so on). So we need a Customer Repository. We also need to find a Location to specify as the destination for the Cargo, so we create a Location Repository.


The Activity Logging Application needs to allow the user to look up the Carrier Movement that a Cargo is being loaded onto, so we need a Carrier Movement Repository. This user must also tell the system which Cargo has been loaded, so we need a Cargo Repository.


Figure 7.4. REPOSITORIES give access to selected AGGREGATE roots.


For now there is no Handling Event Repository, because we decided to implement the association with Delivery History as a collection in the first iteration, and we have no application requirement to find out what has been loaded onto a Carrier Movement. Either of these reasons could change; if they did, then we would add a REPOSITORY.





    [ Team LiB ]



    6.6. Hyperlinks











     < Day Day Up > 







    6.6. Hyperlinks





    Did you know there is a web browser built into the Java editor? Well, there is�sort of. The editor lets you navigate around your program as if it were a web site. Hold down the Ctrl key and move your mouse through your source code. An underline will appear to indicate hyperlinked symbols. You can leave the mouse cursor over the symbol to see its definition, or click on it to open the declaration in the editor.



    Like a browser, Eclipse maintains a history of all the pages you've visited. Use the Back command ( ; Alt+Left; or Navigate Left) to go to the previous location, and use Forward ( ; Alt+Right; or Navigate Right) to go to the next one.















       < Day Day Up > 



      How to Use Formatted Text Fields











       < Day Day Up > 





      How to Use Formatted Text Fields



      Release 1.4 introduced a subclass of JTextField called JFormattedTextField.[55] Formatted text fields provide a way for developers to specify the legal set of characters that can be entered into a text field. Specifically, JFormattedTextField adds a formatter and an object value to the features inherited from JTextField. The formatter performs the translation from the field's value into the text it displays, and vice versa.

      [55] JFormattedTextField API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JFormattedTextField.html.



      Using the formatters Swing provides, you can set up formatted text fields for easy input of dates and numbers in localized formats. Another kind of formatter lets you use a character mask to specify the set of characters that can be entered at each position in the field. For example, you can specify a mask for entering phone numbers in a particular format, such as (XX) X-XX-XX-XX-XX.





      Version Note:

      Before v1.4, text field formatting required more effort. You could check the field's value when the user pressed Enter by putting format-checking code in your action listener, but you couldn't do any checking before the action event was generated unless you implemented a custom model (Document) for the text field. Version 1.3 introduced input verification, but that isn't specialized for text fields and is tied to focus changes. For details, see Validating Input (page 587) in Chapter 9.




      If the possible values of a formatted text field have an obvious order, consider using a spinner instead. A spinner uses a formatted text field, by default, but adds two buttons that let the user step through a sequence of values.



      Another alternative or adjunct to using a formatted text field is installing an input verifier on the field. A component's input verifier is called when the component is about to lose the keyboard focus. It lets you check whether the value of the component is legal and, optionally, change it or stop the focus from being transferred.



      Figure 19 shows a picture of a GUI that uses formatted text fields to display numbers in four different formats.



      Figure 19. The FormattedTextFieldDemo application.




      Try This:













      1. Run FormattedTextFieldDemo using Java Web Start or compile and run the example yourself.[56]

        [56] To run FormattedTextFieldDemo using Java Web Start, click the FormattedTextFieldDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#FormattedTextFieldDemo.

      2. Experiment with different loan amounts, annual percentage rates (APR), and loan lengths. Note that the Monthly Payment field is updated when you either press Enter or move the focus out of the field you're editing, as long as the text that you type is valid.

      3. Enter invalid text such as "abcd" in the Loan Amount field and then press Enter. See, nothing happens. When you move the focus from the field, the text reverts to the field's last valid value.

      4. Enter marginally valid text such as "2000abcd" in the Loan Amount field and press Enter. The Monthly Payment field is updated, though the Loan Amount field still looks strange. When you move the focus from the Loan Amount field, the text it displays is updated to be a nicely formatted version of its value�for example, "2,000" (see Figure 20).



        Figure 20. The Loan Amount field automatically reformats the value "2000abcd" to "2,000."




      Here's the code that creates the first field in FormattedTextFieldDemo:





      amountField = new JFormattedTextField(amountFormat);

      amountField.setValue(new Double(amount));

      amountField.setColumns(10);

      amountField.addPropertyChangeListener("value", this);

      ...

      amountFormat = NumberFormat.getNumberInstance();



      The constructor used to create amountField takes a java.text.Format argument. The Format object is used by the field's formatter to translate between the field's text and value.



      The rest of the code sets up amountField. The setValue method sets the field's value property to a floating-point number represented as a Double object. The setColumns method, inherited from JTextField, provides a hint as to the preferred size of the field. Finally, the call to addPropertyChangeListener registers a listener for the value property of the field so that the program can update the Monthly Payment field whenever the user changes the Loan Amount field.





      Note:

      This section doesn't explain the API inherited from JTextField; that API is described in How to Use Text Fields (page 423).




      Creating and Initializing Formatted Text Fields



      The following code creates and initializes the remaining three fields in FormattedTextFieldDemo.





      rateField = new JFormattedTextField(percentFormat);

      rateField.setValue(new Double(rate));

      rateField.setColumns(10);

      rateField.addPropertyChangeListener("value", this);



      numPeriodsField = new JFormattedTextField();

      numPeriodsField.setValue(new Integer(numPeriods));

      numPeriodsField.setColumns(10);

      numPeriodsField.addPropertyChangeListener("value", this);



      paymentField = new JFormattedTextField(paymentFormat);

      paymentField.setValue(new Double(payment));

      paymentField.setColumns(10);

      paymentField.setEditable(false);

      paymentField.setForeground(Color.red);



      ...

      percentFormat = NumberFormat.getNumberInstance();

      percentFormat.setMinimumFractionDigits(2);



      paymentFormat = NumberFormat.getCurrencyInstance();



      The code for setting up numPeriodsField is almost identical to the code you saw before. The only difference is that the format is slightly different, thanks to the code percent- Format.setMinimumFractionDigits(2).



      The code that creates the numPeriodsField doesn't explicitly set a format or formatter. Instead, it sets the value to an Integer and lets the field use the default formatter for Integers. We couldn't do this in the previous two fields because we didn't want to use the default formatter for Doubles; the result didn't look exactly like we wanted it to. We'll discuss how to specify formats and formatters a little later.



      The payment field is different from the other fields because it's uneditable, uses a different color for its text, and doesn't happen to have a property-change listener. However, it's otherwise the same as the other fields. We could have chosen to use a text field or label instead. Whatever the component, we could still use paymentFormat to parse the payment amount into the text to be displayed.



      Setting and Getting the Field's Value



      Keep this in mind when using a formatted text field:



      A formatted text field's text and its value are two different properties, and the value often lags behind the text.



      The text property is defined by JTextField; it always reflects what the field displays. The value property, defined by JFormattedTextField, might not reflect the latest text displayed in the field. While the user is typing, the text property changes, but the value property doesn't until the changes are committed.



      To be more precise, the value of a formatted text field can be set using either the setValue method or the commitEdit method. The setValue method sets the value to the specified argument. Although the argument can technically be any Object, it needs to be something that the formatter can convert into a string. Otherwise, the text field won't display anything useful.



      The commitEdit method sets the value to whatever object the formatter determines is represented by the field's text. The commitEdit method is automatically called when either of the following happens:



      • When the user presses Enter while the field has the focus.

      • By default, when the field loses the focus�for example, the user presses the Tab key to change the focus to another component. You can use the setFocusLostBehavior method to specify that something different should happen when the field loses the focus.





      Note:

      Some formatters might update the value constantly, making the focus-lost behavior moot since the value will always be the same as what the text specifies.




      When you set the value of a formatted text field, the field's text is updated to reflect the value. Exactly how the value is represented as text depends on the field's formatter.



      Note that although JFormattedTextField inherits the setText method from JTextField, you don't usually invoke setText on a formatted text field. If you do, the field's display will change accordingly but the value will not be updated (unless the field's formatter updates it constantly).



      To get a formatted text field's current value, use the getValue method. If necessary, you can ensure that the value reflects the text by calling commitEdit before getValue. Because getValue returns an Object, you need to cast it to the type used for your field's value. For example, see the following:





      Date enteredDate = (Date)dateField.getValue();



      To detect changes in a formatted text field's value, you can register a property change listener on the formatted text field to listen for changes to the value property. Here's the property change listener from FormattedTextFieldDemo:





      //The property change listener is registered on each

      //field using code like this:

      // someField.addPropertyChangeListener("value", this);



      /** Called when a field's "value" property changes. */

      public void propertyChange(PropertyChangeEvent e) {

      Object source = e.getSource();

      if (source == amountField) {

      amount = ((Number)amountField.getValue()).doubleValue();

      } else if (source == rateField) {

      rate = ((Number)rateField.getValue()).doubleValue();

      } else if (source == numPeriodsField) {

      numPeriods = ((Number)numPeriodsField.getValue()).intValue();

      }



      double payment = computePayment(amount, rate, numPeriods);

      paymentField.setValue(new Double(payment));

      }



      Specifying Formats



      The Format[57] class provides a way to format locale-sensitive information such as dates and numbers. Formatters that descend from InternationalFormatter,[58] such as DateFormatter and NumberFormatter, use Format objects to translate between the field's text and value. You can get a Format object by invoking one of the factory methods in DateFormat or NumberFormat, or by using one of the SimpleDateFormat constructors.

      [57] Format API documentation: http://java.sun.com/j2se/1.4.2/docs/api/java/text/Format.html.

      [58] InternationalFormatter.html API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/text/InternationalFormatter.html.





      Note:

      A third commonly used formatter class, known as MaskFormatter, does not descend from InternationalFormatter and does not use formats. It's discussed in Using MaskFormatter (page 227).




      You can customize certain format aspects when you create the Format, and others through a format-specific API. For example, DecimalFormat objects, which inherit from Number- Format and are often returned by its factory methods, can be customized using the methods setMaximumFractionDigits and setNegativePrefix. For information about using Formats, see the "Formatting" lesson of The Java Tutorial's "Internationalization" trail available on the CD and online at: http://java.sun.com/docs/books/tutorial/i18n/index.html.



      The easiest way to associate a customized format with a formatted text field is to create the field using the JFormattedTextField constructor that takes a Format as an argument. You can see this in the preceding code snippets that create amountField and rateField.



      Using MaskFormatter



      The MaskFormatter[59] class implements a formatter that specifies exactly which characters are legal in each position of the field's text. For example, the following code creates a MaskFormatter that lets the user enter a 5-digit zip code:

      [59] MaskFormatter API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/text/MaskFormatter.html.





      zipField = new JFormattedTextField(

      createFormatter("#####"));

      ...

      protected MaskFormatter createFormatter(String s) {

      MaskFormatter formatter = null;

      try {

      formatter = new MaskFormatter(s);

      } catch (java.text.ParseException exc) {

      System.err.println("formatter is bad: " + exc.getMessage());

      System.exit(-1);

      }

      return formatter;

      }



      You can try out the results of the preceding code by running TextInputDemo. Figure 21 shows the program's GUI. Table 25 shows the characters you can use in the formatting mask.



      Figure 21. The TextInputDemo GUI.




      Table 25. Characters to Use in the Formatting Mask

      Character

      Description

      #

      Any valid number (Character.isDigit).

      '



      (single quote)

      Escape character, used to escape any of the special formatting characters.

      U

      Any character (Character.isLetter). All lowercase letters are mapped to uppercase.

      L

      Any character (Character.isLetter). All uppercase letters are mapped to lowercase.

      A

      Any character or number (Character.isLetter or Character.isDigit).

      ?

      Any character (Character.isLetter).

      *

      Anything.

      H

      Any hex character (0-9, a-f or A-F).



      Specifying Formatters and Using Formatter Factories



      When specifying formatters, keep in mind that each formatter object can be used by at most one formatted text field at a time. Each field should have at least one formatter associated with it, of which exactly one is used at any time.



      You can specify the formatters to be used by a formatted text field in several ways:



      Use the JFormattedTextField constructor that takes a Format argument.


      A formatter for the field that uses the specified format is automatically created.



      Use the JFormattedTextField constructor that takes a JFormattedTextField. AbstractFormatter argument.


      The specified formatter is used for the field.



      Set the value of a formatted text field that has no format, formatter, or formatter factory specified.


      A formatter is assigned to the field by the default formatter factory, using the type of the field's value as a guide. If the value is a Date, the formatter is a DateFormatter. If the value is a Number, the formatter is a NumberFormatter. Other types result in an instance of DefaultFormatter.



      Make the formatted text field use a formatter factory that returns customized formatter objects.


      This is the most flexible approach. It's useful when you want to associate more than one formatter with a field or add a new kind of formatter to be used for multiple fields. As an example of the former use, you might have a field that should interpret user typing in a certain way but display the value (when the user isn't typing) another way. As an example of the latter use, you might have several fields that have values of a custom class�say, PhoneNumber. You could set up the fields to use a formatter factory that can return specialized formatters for phone numbers.



      You can set a field's formatter factory either by creating the field using a constructor that takes a formatter factory argument or by invoking the setFormatterFactory method on the field. To create a formatter factory, you can often use an instance of DefaultFormatter-Factory.[60] A DefaultFormatterFactory object lets you specify the formatters returned when a value is being edited, not being edited, or has a null value.

      [60] DefaultFormatterFactory API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/text/DefaultFormatterFactory.html.



      The pictures in Figure 22 show an application based on FormattedTextFieldDemo that uses formatter factories to set multiple editors for the Loan Amount and APR fields. While the user is editing the Loan Amount, the $ character is not used so that the user isn't forced to enter it. Similarly, while the user is editing the APR field, the % sign is not required.



      Figure 22. In the first FormatterFactoryDemo GUI, the percent symbol (%) is required in the APR field. In the second GUI, the dollar sign ($) is required in the Loan Amount field.




      You can run FormatterFactoryDemo using Java Web Start or compile and run the example yourself.[61]

      [61] To run FormatterFactoryDemo using Java Web Start, click the FormatterFactoryDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#FormatterFactoryDemo.



      Here's the code that creates the formatters and sets them up using instances of Default-FormatterFactory:





      private double rate = .075; //7.5 %

      ...

      amountField = new JFormattedTextField(

      new DefaultFormatterFactory(

      new NumberFormatter(amountDisplayFormat),

      new NumberFormatter(amountDisplayFormat),

      new NumberFormatter(amountEditFormat)));

      ...

      NumberFormatter percentEditFormatter =

      new NumberFormatter(percentEditFormat) {

      public String valueToString(Object o)

      throws ParseException {

      Number number = (Number)o;

      if (number != null) {

      double d = number.doubleValue() * 100.0;

      number = new Double(d);

      }

      return super.valueToString(number);

      }



      public Object stringToValue(String s)

      throws ParseException {

      Number number = (Number)super.stringToValue(s);

      if (number != null) {

      double d = number.doubleValue() / 100.0;

      number = new Double(d);

      }

      return number;

      }

      };



      rateField = new JFormattedTextField(

      new DefaultFormatterFactory(

      new NumberFormatter(percentDisplayFormat),

      new NumberFormatter(percentDisplayFormat),

      percentEditFormatter));

      ...

      amountDisplayFormat = NumberFormat.getCurrencyInstance();

      amountDisplayFormat.setMinimumFractionDigits(0);

      amountEditFormat = NumberFormat.getNumberInstance();



      percentDisplayFormat = NumberFormat.getPercentInstance();

      percentDisplayFormat.setMinimumFractionDigits(2);

      percentEditFormat = NumberFormat.getNumberInstance();

      percentEditFormat.setMinimumFractionDigits(2);



      The boldface code highlights the calls to DefaultFormatterFactory constructors. The first argument to the constructor specifies the default formatter to use for the formatted text field. The second specifies the display formatter, which is used when the field doesn't have the focus. The third specifies the edit formatter, used when the field has the focus. The code doesn't use a fourth argument, but if it did it would specify the null formatter, which is used when the field's value is null. Because no null formatter is specified, the default formatter is used when the value is null.



      The code customizes the formatter that uses percentEditFormat by creating a subclass of NumberFormatter. This subclass overrides the valueToString and stringToValue methods of NumberFormatter so that they convert the displayed number to the value actually used in calculations, and vice versa. Specifically, the displayed number is 100 times the actual value. The reason is that the percent format used by the display formatter automatically displays the text as 100 times the value, so the corresponding editor formatter must do so as well. The first demo, FormattedTextFieldDemo, doesn't need to worry about this conversion because it uses only one format for both display and editing.



      The Formatted Text Field API



      Tables 26 through 28 list some of the commonly used API for using formatted text fields. You can find the relevant API doc at:



      http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JFormattedTextField.html

      http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JFormattedTextField.AbstractFormatter.html

      http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JFormattedTextField.AbstractFormatterFactory.html

      http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/text/DefaultFormatterFactory.html

      http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/text/DefaultFormatter.html

      http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/text/MaskFormatter.html

      http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/text/InternationalFormatter.html

      http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/text/NumberFormatter.html

      http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/text/DateFormatter.html



      Table 26. Classes Related to Formatted Text Fields

      Class

      Purpose

      JFormattedTextField

      Subclass of JTextField that supports formatting arbitrary values.

      JFormattedTextField.AbstractFormatter

      The superclass of all formatters for JFormattedTextField. A formatter enforces editing policies and navigation policies, handles string-to-object conversions, and manipulates the JFormatted-TextField as necessary to enforce the desired policy.

      JFormattedTextField.AbstractFormatterFactory

      The superclass of all formatter factories. Each JFormattedTextField uses a formatter factory to obtain the formatter that best corresponds to the text field's state.

      DefaultFormatterFactory

      The formatter factory normally used. Dishes out formatters based on details such as passed-in parameters and focus state.

      DefaultFormatter

      Subclass of JFormattedTextField.AbstractFormatter that formats arbitrary objects using the toString method.

      MaskFormatter

      Subclass of DefaultFormatter that formats and edits strings using a specified character mask. For example, 7-digit phone numbers can be specified using "###-####".

      InternationalFormatter

      Subclass of DefaultFormatter that uses an instance of java.text.Format to handle conversion to and from a String.

      NumberFormatter

      Subclass of InternationalFormatter that supports number formats using an instance of NumberFormat.

      DateFormatter

      Subclass of InternationalFormatter that supports date formats using an instance of DateFormat.



      Table 27. JFormattedTextField Methods

      Method or Constructor

      Purpose





      JFormattedTextField()

      JFormattedTextField(Object)

      JFormattedTextField(Format)

      JFormattedTextField(AbstractFormatter)

      JFormattedTextField(

      AbstractFormatterFactory)

      JFormattedTextField(

      AbstractFormatterFactory,

      Object)

      Create a new formatted text field. The Object argument, if present, specifies the initial value of the field and causes an appropriate formatter factory to be created. The Format or AbstractFormatter argument specifies the format or formatter to be used for the field, causing an appropriate formatter factory to be created. The AbstractFormatterFactory argument specifies the formatter factory to be used, which determines which formatters are used for the field.





      void setValue(Object)

      Object getValue()

      Set or get the value of the formatted text field. You must cast the return type based on how the JFormattedTextField has been configured. If the formatter hasn't been set yet, invoking setValue sets the formatter to one returned by the field's formatter factory.





      void setFormatterFactory(

      AbstractFormatterFactory)

      Set the object that determines the formatters used for the formatted text field. It is often an instance of DefaultFormatterFactory.

      AbstractFormatter getFormatter()

      Get the formatter of the formatted text field. It is often an instance of DefaultFormatter.

      void setFocusLostBehavior(int)

      Specifies what should happen when the field loses the focus. Possible values are defined in JFormattedTextField as COMMIT_OR_REVERT (the default), COMMIT (commit if valid, otherwise leave everything the same), PERSIST (do nothing), and REVERT (change the text to reflect the value).

      void commitEdit()

      Sets the value to the object represented by the field's text (as determined by the field's formatter). If the text is invalid, the value remains the same and a ParseException is thrown.

      boolean isEditValid()

      Returns true if the formatter considers the current text to be valid (as determined by the field's formatter).



      Table 28. DefaultFormatter Options

      Method

      Purpose





      void setCommitsOnValidEdit(boolean)

      boolean getCommitsOnValidEdit()

      Set or get when edits are pushed back to the JFormattedTextField. If true, commitEdit is invoked after every valid edit. This property is false by default.





      void setOverwriteMode(boolean)

      boolean getOverwriteMode()

      Set or get the behavior when inserting characters. If true, new characters overwrite existing characters in the model as they are inserted. The default value of this property is true in DefaultFormatter (and thus in MaskFormatter) and false in InternationalFormatter (and thus in Date-Formatter and NumberFormatter).





      void setAllowsInvalid(boolean)

      boolean getAllowsInvalid()

      Set or get whether the value being edited is allowed to be invalid for a length of time. It is often convenient to allow the user to enter invalid values until a commit is attempted. DefaultFormatter initializes this property to true. Of the standard Swing formatters, only MaskFormatter sets it to false.



      Examples That Use Formatted Text Fields



      A few of our examples use formatted text fields.



      Example

      Where Described

      Notes

      FormattedTextFieldDemo

      This section

      Uses four formatted text fields.

      SpinnerDemo

      How to Use Spinners (page 357)

      Customizes the appearance of the formatted text fields used by two spinners.

      SliderDemo3

      How to Use Sliders (page 348)

      Pairs a formatted text field with a slider to allow editing of an integer value.

      Converter

      Using Models (page 50)

      Each ConversionPanel pairs a formatted text field with a slider.

      CelsiusConverter2

      Example Four: An Improved CelsiusConverter (page 22)

      Uses a formatted text field to let the user enter a decimal number.

      TextInputDemo

      This section

      Shows how to use text fields, spinners, and formatted text fields together, and demonstrates how to use MaskFormatter. Includes code for selecting the text of the field that has just gotten the focus.

      FormatterFactoryDemo

      This section

      A variation on FormattedTextFieldDemo that uses formatter factories to specify multiple formatters for two formatted text fields.

      RegexFormatter

      "Regular Expression Based AbstractFormatter," a Swing Connection article online at: http://java.sun.com/products/jfc/tsc/articles/reftf/

      A regular expression formatter that you can use. Includes source code and information on how it was implemented.













         < Day Day Up > 



        Chapter 5. Testing and Debugging











         < Day Day Up > 









        Chapter 5. Testing and Debugging







          Introduction



          Section 5.1. 

          Installing JUnit



          Section 5.2. 

          Testing an Application with JUnit



          Section 5.3. 

          Starting a Debugging Session



          Section 5.4. 

          Setting a Breakpoint



          Section 5.5. 

          Stepping Through Your Code



          Section 5.6. 

          Running Until Encountering a Breakpoint



          Section 5.7. 

          Running to a Line of Code You Select



          Section 5.8. 

          Watching Expressions and Variables



          Section 5.9. 

          Setting a Hit Count for Breakpoints



          Section 5.10. 

          Configuring Breakpoint Conditions



          Section 5.11. 

          Creating Field, Method, and Exception Breakpoints



          Section 5.12. 

          Evaluating Expressions



          Section 5.13. 

          Assigning Values to Variables While Debugging



          Section 5.14. 

          Changing Code on the Fly











         < Day Day Up > 



        Section 13.2.&nbsp; Daemon Characteristics










        13.2. Daemon Characteristics


        Let's look at some common system daemons and how they relate to the concepts of process groups, controlling terminals, and sessions that we described in Chapter 9. The ps(1) command prints the status of various processes in the system. There are a multitude of optionsconsult your system's manual for all the details. We'll execute




        ps -axj



        under BSD-based systems to see the information we need for this discussion. The -a option shows the status of processes owned by others, and -x shows processes that don't have a controlling terminal. The -j option displays the job-related information: the session ID, process group ID, controlling terminal, and terminal process group ID. Under System Vbased systems, a similar command is ps -efjc. (In an attempt to improve security, some UNIX systems don't allow us to use ps to look at any processes other than our own.) The output from ps looks like


        PPID

        PID

        PGID

        SID

        TTY

        TPGID

        UID

        COMMAND

        0

        1

        0

        0

        ?

        -1

        0

        init

        1

        2

        1

        1

        ?

        -1

        0

        [keventd]

        1

        3

        1

        1

        ?

        -1

        0

        [kapmd]

        0

        5

        1

        1

        ?

        -1

        0

        [kswapd]

        0

        6

        1

        1

        ?

        -1

        0

        [bdflush]

        0

        7

        1

        1

        ?

        -1

        0

        [kupdated]

        1

        1009

        1009

        1009

        ?

        -1

        32

        portmap

        1

        1048

        1048

        1048

        ?

        -1

        0

        syslogd -m 0

        1

        1335

        1335

        1335

        ?

        -1

        0

        xinetd -pidfile /var/run/xinetd.pid

        1

        1403

        1

        1

        ?

        -1

        0

        [nfsd]

        1

        1405

        1

        1

        ?

        -1

        0

        [lockd]

        1405

        1406

        1

        1

        ?

        -1

        0

        [rpciod]

        1

        1853

        1853

        1853

        ?

        -1

        0

        crond

        1

        2182

        2182

        2182

        ?

        -1

        0

        /usr/sbin/cupsd



        We have removed a few columns that don't interest us, such as the accumulated CPU time. The column headings, in order, are the parent process ID, process ID, process group ID, session ID, terminal name, terminal process group ID (the foreground process group associated with the controlling terminal), user ID, and command string.



        The system that this ps command was run on (Linux) supports the notion of a session ID, which we mentioned with the setsid function in Section 9.5. The session ID is simply the process ID of the session leader. A BSD-based system, however, will print the address of the session structure corresponding to the process group that the process belongs to (Section 9.11).



        The system processes you see will depend on the operating system implementation. Anything with a parent process ID of 0 is usually a kernel process started as part of the system bootstrap procedure. (An exception to this is init, since it is a user-level command started by the kernel at boot time.) Kernel processes are special and generally exist for the entire lifetime of the system. They run with superuser privileges and have no controlling terminal and no command line.


        Process 1 is usually init, as we described in Section 8.2. It is a system daemon responsible for, among other things, starting system services specific to various run levels. These services are usually implemented with the help of their own daemons.


        On Linux, the kevenTD daemon provides process context for running scheduled functions in the kernel. The kapmd daemon provides support for the advanced power management features available with various computer systems. The kswapd daemon is also known as the pageout daemon. It supports the virtual memory subsystem by writing dirty pages to disk slowly over time, so the pages can be reclaimed.


        The Linux kernel flushes cached data to disk using two additional daemons: bdflush and kupdated. The bdflush daemon flushes dirty buffers from the buffer cache back to disk when available memory reaches a low-water mark. The kupdated daemon flushes dirty pages back to disk at regular intervals to decrease data loss in the event of a system failure.


        The portmapper daemon, portmap, provides the service of mapping RPC (Remote Procedure Call) program numbers to network port numbers. The syslogd daemon is available to any program to log system messages for an operator. The messages may be printed on a console device and also written to a file. (We describe the syslog facility in Section 13.4.)


        We talked about the inetd daemon (xinetd) in Section 9.3. It listens on the system's network interfaces for incoming requests for various network servers. The nfsd, lockd, and rpciod daemons provide support for the Network File System (NFS).


        The cron daemon (crond) executes commands at specified dates and times. Numerous system administration tasks are handled by having programs executed regularly by cron. The cupsd daemon is a print spooler; it handles print requests on the system.


        Note that most of the daemons run with superuser privilege (a user ID of 0). None of the daemons has a controlling terminal: the terminal name is set to a question mark, and the terminal foreground process group is 1. The kernel daemons are started without a controlling terminal. The lack of a controlling terminal in the user-level daemons is probably the result of the daemons having called setsid. All the user-level daemons are process group leaders and session leaders and are the only processes in their process group and session. Finally, note that the parent of most of these daemons is the init process.










          The StreamTokenizer Class




          I l@ve RuBoard









          The StreamTokenizer Class


          StreamTokenizer breaks up an input stream into tokens and can be used to parse a simple file (excuse me, "input stream"). Read the Java API documentation on StreamTokenizer, and then compare what you read to the following methods



          • __init__(Reader)


          • __init__(InputStream)


          • nextToken()
            returns the next token in the stream



          • lineno()
            returns the current line number



          • lowerCaseMode(flag)
            returns all words to lowercase if passed a true value



          • parseNumbers()
            sets the parsing of floating-point numbers



          • pushBack()
            pushes the token back onto the stream, returning it to the next nextToken() method call



          • quoteChar(char)
            specifies the character string delimiter; the whole string is returned as a token in sval



          • resetSyntax()
            sets all characters to ordinary so that they aren't ignored as tokens



          • commentChar(char)
            specifies a character that begins a comment that lasts until the end of the line; characters in a comment are not returned



          • slashSlashComments(flag)
            allows recognition of // to denote a comment (this is a Java comment)



          • slashStarComments(flag)
            allows recognition of /* */ to denote a comment



          • toString()


          • whitespaceChars(low,hi)
            specifies the range of characters that denote delimiters



          • wordChars(low, hi)
            specifies the range of characters that make up words



          • ordinaryChar(char)
            specifies a character that is never part of a token (the character should be returned as is)



          • ordinaryChars(low, hi)
            specifies a range of characters that are never part of a token (the character should be returned as is)



          • eolSignificant(flag)
            specifies if end-of-line (EOL) characters are significant (they're ignored if not, i.e., treated like whitespace)




          StreamTokenizer's variables are ttype (one of the constant values TT_EOF, TT_EOL, TT_NUMBER, and TT_WORD); sval (contains the token of the last string read); and nval (contains the token of the last number read).


          Using StreamTokenizer


          Reading the documentation probably isn't enough to get you started with StreamTokenizer, so we're going to work with a simple application that produces a report on the number of classes and functions in a Python source file. Here's the source code:



          class MyClass: #This is my class
          def method1(self):
          pass
          def method2(self):
          pass

          #Comment should be ignored
          def AFunction():
          pass

          class SecondClass:
          def m1(self):
          print "Hi Mom" #Say hi to mom
          def m2(self):
          print "Hi Son" #Say hi to Son

          #Comment should be ignored
          def BFunction():
          pass

          Follow along with the next interactive session. Afterward we'll look at the code to count the classes and functions.


          Import the FileInputStream class from java.io, and create an instance of it.



          >>> from java.io import FileInputStream
          >>> file = FileInputStream("C:\\dat\\ParseMe.py")

          Import the StreamTokenizer class, and create an instance of it. Pass its constructor the FileInputStream instance.



          >>> from java.io import StreamTokenizer
          >>> token = StreamTokenizer(File)

          Call nextToken() to get the first token in the file (that is, class).



          >>> token.nextToken()
          -3

          As you can see, nextToken() returns a numeric value, although you may have been expecting a string value containing "class". In fact, nextToken() returns the type of token, that is, a word, a number, or an EOL or EOF (end-of-file) character, so -3 refers to TT-WORD.


          The ttype variable holds the last type of token read.



          >>> token.ttype
          -3

          The sval variable holds the actual last token read. If we want to check if the last token type was a word, we can write this, and, if it was a word, we can print it out.



          >>> if token.ttype == token.TT_WORD:
          ... print token.sval
          ...
          class
          >>>

          Call nextToken() again to get the next token, which is MyClass.



          >>> token.nextToken()
          -3

          >>> print token.sval
          MyClass

          Call nextToken() again; this time it should return the '#' token.



          >>> token.nextToken()
          58

          >>> print token.sval
          None

          Since the token is a ':' StreamTokenizer doesn't recognize it as valid. The only valid types are NUMBER, EOL, EOF, and WORD. So for ':' to be recognized, it has to be registered with the wordChars() method.



          >>> token.TT_NUMBER
          -2

          >>> token.TT_EOL
          10

          >>> token.TT_EOF
          -1

          >>> token.TT_WORD
          -3

          If the type isn't one of these, the number corresponding to the character encoding is returned. Let's see what nextToken() returns for the next character.



          >>> token.nextToken()
          35

          The 35 refers to '#', which you can prove with the built-in ord() function.



          >>> ord('#')
          35

          Get the next token.



          >>> token.nextToken()
          -3

          The token is a word (-3 equates to TT_WORD). Print sval to find out what the word is.



          >>> print token.sval
          This

          As you can see, the StreamTokenizer instance is reading text out of the comment from the first line. We want to ignore comments, so we need to return the tokens we took out back into the stream.


          Push the token back into the stream.



          >>> token.pushBack()

          Attempt to push the token before the last one back into the stream.



          >>> token.pushBack()

          Set commentChar() to ignore '#'. (commentChar() takes an integer argument corresponding to the encoding of the character.)



          >>> token.commentChar(ord('#'))

          Get the next token, and print it out.



          >>> token.nextToken()
          -3

          >>> print token.sval
          This

          Are you wondering why we still have the comment text? The pushback() method can only push back the last token, so calling it more than once won't do any good. Let's start from the beginning, creating a new FileInputStream instance and a new StreamTokenizer instance.


          Create the StreamTokenizer instance by passing its constructor a new instance of FileInputStream.



          >>> file = fileInputStream("c:\\dat\\parseMe.py")
          >>> token = StreamTokenizer(File)

          Iterate through the source code, printing out the words in the file. Quit the while loop when the token type is EOF.



          >>> while token.ttype != token.TT_EOF:
          ... token.nextToken()
          ... if(token.ttype == token.TT_WORD):
          ... print token.sval

          Notice that the comment text isn't in the words printed out.



          class
          MyClass
          def
          method1
          self
          pass
          def
          method2
          self
          pass
          def
          AFunction
          pass
          ...
          ...


          Parsing Python with StreamTokenizer


          Okay, we've done our experimentation. Now it's time for the actual code for counting the classes and functions in our Python source code.



          from java.io import FileInputStream, StreamTokenizer

          # Create a stream tokenizer by passing a new
          # instance of the FileInputStream
          token = StreamTokenizer(FileInputStream("c:\\dat\\parseMe.py"))

          # Set the comment character.
          token.commentChar(ord('#'))

          classList = []
          functionList = []

          # Add an element to a list
          def addToList(theList, token):
          token.nextToken()
          if (token.ttype == token.TT_WORD):
          theList.append (token.sval)

          # Adds a class to the class list
          def parseClass(token):
          global classList
          addToList (classList, token)

          # Adds a function to the function list
          def parseFunction(token):
          global functionList
          addToList (functionList, token)

          # Iterate through the list until the
          # token is of type TT_EOF, end of File
          while token.ttype != token.TT_EOF:
          token.nextToken()
          if(token.ttype == token.TT_WORD):
          if (token.sval == "class"):
          parseClass(token)
          elif(token.sval == "def"):
          parseFunction(token)

          # Print out detail about a function or class list
          def printList(theList, type):
          print "There are " + `len(theList)` + " " + type
          print theList

          # Print the results.
          printList (classList, "classes")
          printList (functionList, "functions and methods")

          Here's the output:



          There are 2 classes
          ['MyClass', 'SecondClass']
          There are 6 functions and methods
          ['method1', 'method2', 'AFunction', 'm1', 'm2', 'BFunction']

          The main part of the code (where all the action is happening) is



          # Iterate through the list until the
          # token is of type TT_EOF, end of File
          while token.ttype != token.TT_EOF:
          token.nextToken()
          if(token.ttype == token.TT_WORD):
          if (token.sval == "class"):
          parseClass(token)
          elif(token.sval == "def"):
          parseFunction(token)

          Let's look at it step by step.


          If the token type isn't equal to EOF, get the next token.



          while token.ttype != token.TT_EOF:
          token.nextToken()

          If the token type is WORD,



          if(token.ttype == token.TT_WORD):

          check to see if the token is a class modifier. If it is, call the parseClass() function, which uses the StreamTokenizer instance to extract the class name and put it on a list.



          if (token.sval == "class"):
          parseClass(token)

          If the token isn't a class modifier, check to see if it's a function modifier. If so, call parseFunction(), which uses StreamTokenizer to extract the function name and put it on a list.



          elif(token.sval == "def"):
          parseFunction(token)

          StreamTokenizer is a good way to parse an input stream. If you understand its runtime behavior (which you should from the preceding interactive session), you'll be more likely to use it.


          The more astute among you probably noticed that functions and methods were counted together in the last example. As an exercise, change the code so that each class has an associated list of methods and so that these methods are counted separately.


          Hint: You'll need to use the resetSyntax() method of StreamTokenizer to set all characters to ordinary. Then you'll need to count the spaces (ord(")) and tabs (ord("\t")) that occur before the first word on a line. For this you also need to track whether you hit an EOL token type. (If you can do this exercise, I do believe that you can do any exercise in the book.)


          As another exercise, create a stream that can parse a file whose contents look like this:



          [SectionType:SectionName]
          value1=1
          value2 = 3 #This is a comment that should be ignored
          value4 = "Hello"

          SectionType defines a class of section, and SectionName is like defining a class instance. value equates to a class attribute.


          Here's an example.



          [Communication:Host]
          type = "TCP/IP" #Possible values are TCP/IP or RS-232
          port = 978 #Sets the port of the TCP/IP

          [Communication:Client]
          type = "RS-232"
          baudrate = 9600
          baudrate = 2800
          baudrate = 19200

          [Greeting:Client]
          sayHello = "Good morning Mr. Bond"

          [Greeting:Host]
          sayHello = "Good morning sir"

          Create a dictionary of dictionaries of dictionaries. The name of the top-level dictionary should correspond to the section type (Communication, Greeting); its value should be a dictionary whose name corresponds to the section names (Client, Host) and whose values correspond to another dictionary. The names and values of the third-level dictionaries should correspond to the name values in the file (sayHello = "Good morning Mr. Bond", type = "RS-232"). If, like baudrate, the name repeats itself, you should create a list corresponding to the name baudrate and, instead of a single value inserted in the bottom-tier dictionaries, put the list as the value.


          The structure will look like this:



          {}�Communication���{}�� Client {}� type = "rs-232"
          | | |
          | | - baudrate = [9600, 2800, 19200]
          | |
          | |� Host {} � type = "TCP/IP"
          | |
          | - port = 978
          |
          Greeting �����-----{} - Client{} - sayHello = "Good morning Mr. Bond"
          |
          |� Host � sayHello = "Good morning sir"








            I l@ve RuBoard



            9.5. Four in Four: It Just Won't Go



            9.5. Four in Four: It Just Won't Go


            Many of
            the problems that we have come across while developing and designing JPC have
            been those associated with overhead. When trying to emulate a full computing
            environment inside itself, the only things that prevent you from extracting 100%
            of the native performance are the overheads of the emulation. Some of these
            overheads are time related such as in the processor emulation, whereas others
            are space related.


            The most obvious place where
            spatial overheads cause a problem is in
            the address space: the 4 GB memory space (32-bit addresses) of a virtual
            computer won't fit inside the 4 GB (or less) available in real (host) hardware.
            Even with large amounts of host memory, we can't just declare byte[] memory
            = new byte[4 * 1024 * 1024 * 1024];
            . Somehow we
            must shrink our emulated address space to fit inside a single process on the
            host machine, and ideally with plenty of room to spare!


            To save space, we first observe that
            the 4 GB address space is invariably not full. The typical machine will not
            exceed 2 GB of physical RAM, and we can get away with significantly less than
            this in most circumstances. So we can crush our 4 GB down quite quickly by
            observing that not all of it will be occupied by physical RAM.


            The first step in designing our
            emulated physical address space has its origin in a little peek at the future.
            If we look up the road we will see that one of the features of the IA-32 memory
            management unit will help guide our structure for the address space. In
            protected mode, the memory management unit of the CPU carves the address space
            into indivisible chunks that are 4 KB wide (known as pages). So the obvious
            thing to do is to chunk our memory on the same scale.


            Splitting our address space into 4 KB
            chunks means our address space no longer stores the data directly. Instead, the
            data is stored in atomic memory units, which are represented as various
            subclasses of Memory. The address space then
            holds references to these objects. The resultant structure and memory accesses
            are shown in Figure 9-2.




            Note: To optimize instanceof lookups, we
            design the inheritance chain for Memory objects without using
            interfaces.





            Figure 9-2. Physical
            address space block structure




            This structure has a set of
            220 blocks, and each block will require a
            32-bit reference to hold it. If we hold these in an array (the most obvious
            choice), we have a memory overhead of 4 MB, which is not significant for most
            instances.






            Tip #7: instanceof is faster
            on classes


            Performing
            instanceof on a class is far quicker than
            performing it on an interface. Java's single inheritance model means that on a
            class, instanceof is simply one subtraction and
            one array lookup; on an interface, it is an array
            search.



            Where this overhead is a problem, we can
            make further optimizations. Observe that memory in the physical address space
            falls into three distinct categories:





            RAM



            Physical RAM is mapped from the zero
            address upward. It is frequently accessed and low latency.




            ROM



            ROM chips can exist at any address.
            They are infrequently accessed and low latency.




            I/O



            Memory-mapped I/O can exist at any
            address. It is fairly frequently accessed, but is generally higher latency than
            RAM.


            For addresses that fall within the
            RAM of the real machine, we use a one-stage lookup. This ensures that accesses
            to RAM are as low latency as possible. For accesses to other addresses, those
            occupied by ROM chips and memory-mapped I/O, we use a two-stage lookup, as in Figure
            9-3.



            Figure 9-3. Physical
            address space with a two-stage lookup




            Now a memory "get" from RAM has three
            stages:

            return addressSpace.get(address);
            return blocks[i >>> 12].get(address & 0xfff);
            return memory[address];


            And one from a higher address has
            four:

            return addressSpace.get(address);
            return blocks[i >>> 22][(i >>> 12) & 0x3ff].get(address & 0xfff);
            return memory[address];


            This two-layer optimization has saved
            us memory while avoiding the production of a bottleneck in every RAM memory
            access. Each call and layer of indirection in a memory "get" performs a
            function. This is indirection the way it should be used—not for the sake of
            interfacing, but to achieve the finest balance of performance and footprint.


            Lazy initialization is also used in JPC wherever there is chance of storage
            never being used. Thus a new JPC instance has a physical address space with
            mappings to Memory objects that occupy no space.
            When a 4 KB section of RAM is read from or written to for the first time, the
            object is fully initialized, as in Example 9-1.


            Example 9-1. Lazy
            initialization




            public byte getByte(int offset)
            {
            try {
            return buffer[offset];
            } catch (NullPointerException e) {
            buffer = new byte[size];
            return buffer[offset];
            }
            }


             


            Section 5.1.&nbsp; Plan of Action










            5.1. Plan of Action



            5.1.1. Program Tasks


            We'll use Linrg unchanged for the computational part of the program. Our front-end program will therefore have the tasks of


            • Storing a list of x and y data pairs

            • Allowing the user to enter and edit the data-pair list

            • Passing the data-pair list to Linrg

            • Reading the results from Linrg and displaying them to the user



            Keeping Linrg as a separate executable is admittedly a strange decision: The code is so simple, it would be easier to fold it into the main application. We're doing it this way in order to illustrate a few additional points. If Linrg were a large-address-space application, using a 64-bit address space under Mac OS X 10.4 or later, it might make sense to build it as a 64-bit utility, with a 32-bit application running its human interface.






            5.1.2. Model-View-Controller


            Cocoa applications are built around the design pattern called Model-View-Controller (MVC). The pattern asserts that three kinds of things comprise an interactive program.


            1. Model objects embody the data and logic of a particular problem domain. Models tend to be unique to each application.

            2. View objects handle user interaction, presenting information and enabling the user to manipulate data or otherwise influence the behavior of the program. Views are usually drawn from a repertoire of standard elements, such as buttons, tables, scrollers, and text areas. Views tend to have no intelligence about any particular problem domain: A button can display itself and report button clicks without having to know what clicking would mean in your application.

            3. Controller objects mediate between the pure logic of the model and the pure mechanics of the views. A controller object decides how model content will be displayed by the views and how user actions translate into model events.



            The Model

            It seems plain that the first task of our programstoring a list of data pairsis the sort of task a model object performs. Similarly, the task of calculating the linear regression is purely a function of the data we present to the calculation and would be the same no matter how we managed the data points beforehand or presented the results afterward.


            What we want, then, is a document containing a set of data points and the results of calculating a linear regression on them. This simple design is shown in Figure 5.1.



            Figure 5.1. The minimal data model for a program that manages linear regressions. The document contains a list of data points and the results of the regression done on them. The regression refers to the list of data points.







            We will be working in Objective-C, which provides the easiest access to Cocoa. From the figure, it's natural to imagine the interface for a DataPoint object:


            @interface DataPoint : NSObject <NSCoding> {
            double x;
            double y;
            }

            - (id) init;
            - (id) initWithX: (double) xValue Y: (double) yValue;

            - (double) x;
            - (void) setX: (double) newValue;
            - (double) y;
            - (void) setY: (double) newValue;
            @end


            This code segment declares DataPoint to be a subclass of the basic NSObject class, promises that DataPoint will be able to read and write itself in data streams according to the NSCoding protocol, and says that its data consists of two double-precision numbers: x and y. The code then declares a default initializer (init) and an initializer that sets the instance values (initWithX:Y:). After that come accessors for reading and setting the x and y values. Simple.


            The interface for the Regression class is mostly the same concept, applied to the four data members instead of two:


            @interface Regression : NSObject <NSCoding> {
            NSMutableArray * dataPoints;
            double slope;
            double intercept;
            double correlation;

            NSTask * linrgTask;
            }

            - (id) init;

            - (double) slope;
            - (void) setSlope: (double) aSlope;
            - (double) intercept;
            - (void) setIntercept: (double) anIntercept;

            - (double) correlation;
            - (void) setCorrelation: (double) aCorrelation;

            - (NSMutableArray *) dataPoints;
            - (void) setDataPoints: (NSMutableArray *) aDataPoints;

            - (BOOL) canCompute;
            - (void) computeWithLinrg;
            @end


            Once again, we see the descent from NSObject, the promise of NSCoding, the four data members, and accessor methods for those members. We make dataPoints an NSMutableArray, which is a Cocoa class that keeps ordered lists of objects. There are two additional public methods.


            1. The method canCompute returns YESthe Objective-C equivalent of trueonly if at least two data points are available. This isn't a comprehensive test for whether the regression would be valid, but it's a start.

            2. The method computeWithLinrg calculates the slope, intercept, and correlation coefficient.


            One data member, linrgTask, didn't figure in our sketch model. This data member is an NSTask, an object used for running command line tools from Cocoa applications. We'll be using an NSTask to run Linrg on our data points.




            The Controller

            The controller object we create will be an instance of MyDocument, a subclass of Cocoa's NSDocument. Xcode's template for a new Cocoa document-based application automatically includes a MyDocument class with skeleton code in the project.


            NSDocuments are automatically placed in the command-response chain of the application and bring with them the basics of loading and storing a document's contents in the file system. We can expect our documents to be told to load and store themselves, to compute the linear regression, and to add, edit, and remove data points. Therefore, we will want to provide methods for loading and storing and for computing. These tasks can be done through Regression, our top-level model object, so we conclude that MyDocument need add a data member only for a Regression object.



            Accessorizer


            Note that for every property named propertyName of type type in a class, the key-value coding (KVC) protocol has us writing a pair of methods:


            • (type) propertyName;

            • (void) setPropertyName: (type) aValue;


            The individual methods are not difficult to writethey are almost identicalbut they are tedious. Can't we automate the task of generating property accessors?


            We can. The first resort is to Xcode's Script menuit appears in the menu bar as a scrollin the Code submenu. Select the four lines that declare Regression's instance variables, and select Script Code Place Accessor Decls on Clipboard. You can now paste declarations for setter and getter methods for each of the three instance variables into the header. Reselect the instance-variable declarations, and select Place Accessor Defs on Clipboard so you can paste the complete methods into the implementation file.


            Kevin Callahan's Accessorizer application is a more comprehensive tool for generating accessors and many other kinds of boilerplate code for Cocoa. (Visit his site at http://www.kevincallahan.org/software/accessorizer.html) The application can be configured extensively to fit almost any style of code layout and philosophy of architecture for accessors. If you do a lot of Cocoa programming, Accessorizer will make your life easier and be worth the donation the author asks.




            Strangely, we won't be providing any methods for managing the data points. More on this later.


            @class Regression;

            @interface MyDocument : NSDocument
            {
            Regression * model;
            }
            - (IBAction) compute: (id) sender;
            @end


            By the vagaries of the Objective-C language, it is not necessary to declare in the interface every method a class implements. One method we do need to declare is compute:, the method that triggers calculation of the regression. As a method that responds to commands from the application's human interface, compute: follows a strict signaturetaking one anonymous object (type id), the sender of the command, and returning IBAction, which is #defined as void but serves to inform Interface Builder that this command may be issued to this class by the human interface.




            The View(s)

            The view layer of our program is best specified by how we want it to look and behave. Figure 5.2 shows what we're aiming for.



            Figure 5.2. Planned layout of the main window of our linear-regression program. The Add and Remove buttons insert and delete points in the data set, which can be edited directly in the table at left. The Compute button passes the points to Linrg and causes the results to be displayed in the read-only fields below it.