Saturday, July 1, 2017

The Power is Yours!

Every computer has a box called a power supply, which is responsible for supplying electricity to the internal components of the computer. Its main task is to convert the AC (alternating current) power from the electrical outlet to DC (direct current) power, and then dole out the DC power to the computer's internal components. Different parts of the world use different voltage standards for their electrical outlets, so a power supply has to be compatible with the voltage standards in your part of the world. For example, power outlets in North America run at around 115V, and those in Europe generally run at around 230V. Some power supplies have a physical switch on the outside that tell it what voltage to expect (called fixed-input). Others will adjust automatically (called auto-switching).

Due to the nature of AC power, power supplies can take damage over time from something called harmonics. Harmonics is caused by the way in which electrical devices draw power from an AC connection, and is what causes electrical devices to make faint humming sounds. Most power supplies come with circuitry that protect against this, called active power factor correction (active PFC). You should never buy a power supplies that does not have this.

I need more power, Captain!

Every power supply has a maximum amount of wattage it can draw. If the internal components of the computer try to draw more than that, the computer won't work right. For example, if you want to install a brand new, high performance graphics card, you should make sure your power supply has enough available voltage. Note that power supplies are replaceable, so if your current power supply isn't good enough, you can always replace it.

Power supplies do not use all of the AC power it consumes. Some power is lost due to inefficiencies and released in the form of heat. Most power supplies are at least 80% efficient, and they will advertise what their efficiency is on the packaging. A more efficient power supply will consume less power.

It's important to note that power supplies only draw the amount of energy that is actually being used by the computer—they do NOT draw the maximum amount they are capable of. For example, if you have a power supply can that provide a max of 500 W and your computer is only using 200 W, then the power supply will only draw enough power for 200 W. You won't be wasting electricity if you buy a power supply that can supply more power than your computer needs. In fact, it is good to have a such a power supply for two reasons: (1) To allow room for future upgrades and (2) to account for the fact that power supplies produce less wattage over time due to wear and tear.

Rails

The DC power that the power supply generates is doled out through three voltage rails. Each rail supplies a different voltage: 12V, 5V, and 3.3V. The 12V rail is typically used to power devices that have motors of some sort, such as hard disk drives and optical drives, but there is no restriction regarding what each voltage rail can be used for (for example, a high-end graphics card might want to use the 12V rail).

Each rail has a maximum amount of amperage it supports, and this is monitored by circuitry called over-current protection (OCP). Single-rail systems have a single OCP that monitors all the rails. Multi-rail systems have one OCP per rail to monitor each rail. If the amperage in any rail is exceeded, the power supply will shut itself off to prevent damage to itself.  When multi-rail systems were first introduced, they were very unstable due to poorly written specifications, but they have gotten much better since then.  For computers that use a lot of power, like servers and gaming PCs, multi-rail systems give your system extra protection against short-circuits.  For an ordinary, low-wattage desktop PCs, it doesn't really make a difference whether you have a single-rail or multi-rail system.

Power supply standards

Various power supply standards have been released over the years. ATX (also called ATX12V) introduced the idea of providing a constant supply of power (5V) to the motherboard, even when the computer is off. This is called soft power, and it allows the computer to implement various power saving features. This is the reason why you always should always unplug a computer before servicing it! This standard was later improved upon by subsequent standards (below).

ATX12V 1.3 added the P4 connector, which supplies extra power to the motherboard. It also added the AUX connector. The downside to this standard was that it was not specific enough, which resulted in power supply manufacturers producing wildly different power supplies.

EPS12V was created for servers that need more power than the average desktop machine. It added a 24-pin motherboard power connector. It also introduced the idea of “voltage rails” (explained above).

ATX12V 2.0 adopted many of the advancements that EPS12V brought to the table. Notably, it added a 24-pin P1 connector and voltage rails.

Connectors

Many of the different connectors you will see coming out of a power supply are listed in the table below. Yeah! Tables!

Connector Voltages Pins Description
P1 power connector 3.3V, 5V, 12V 20/24 The older variant of this connector has 20 pins. The newer variant (which is backward compatible) has 24 pins and provides more current.

Molex 5V, 12V 4 Typically used to power storage devices, like hard drives.

Mini 5V, 12V 4 This connector used to be used for 3.5” floppy disk drives and isn't used much anymore. You have to be careful when plugging in this connector because it is easy to plug in upside down, which will ruin the device.

SATA power connector 3.3V, 5V, 12V 15 Only used for SATA hard drives. In practice, only the 5 V and 12V voltages are used.

SATA slimline connector 5V 6 A smaller version of the SATA power connector.

SATA micro connector 3.3, 5V 9 Even smaller!  Can't reliably find a photo of this one.
P4 connector 12V 4 Used in conjunction with a 20-pin P1 connector to supply the motherboard with extra power.

AUX connector 3.3V, 5V 6 Also used for supply the motherboard with extra power.

EPS12V
EATX12V
ATX12V 2x4
12V 8 This connector goes by many different names. One half is compatible with the P4 connector.

PCIe Connector 12V 6/8 In some 8-pin connectors, two of the pins are detachable so make them compatible with the 6-pin version. It looks similar to the EPS12V connector, but is not compatible with it.


References

Sunday, June 25, 2017

Computer Networks 101

In your typical white-collar work environment, each employee has a computer at their desk. The computers are connected with each other over a LAN (local area network). If you have internet access at home, the computers in your house are most likely organized into a LAN as well. A LAN is a group of computers that are physically close to one another and that can communicate with each other over a network.  All of the computers in a LAN are said to belong to a broadcast domain, which means that if one computer sends out a broadcast message, then all the other computers can hear it.

Ethernet

One of the most common ways to join computers into a LAN is to use Ethernet. There are four properties of an Ethernet cable: EMI resistance, heat resistance, flexibility, and speed.

EMI resistance: STP (shielded twisted pair) cables are designed to protected again EMI (electromagnetic interference). A shop floor is a good example of a place where STP cables should be used because it has lots of electrical motors and other machinery. However, the vast majority of environments do not require significant protection from EMI, so they use UTP (unshielded twisted pair) cables, which are less expensive.

Heat resistance: Ethernet cabling is often run through the walls and ceilings of a building (called plenum space) in order to keep the cables out of the way. These areas of the building can get very hot. The rubbery outside of an Ethernet cable is typically made with a material called PVC. If PVC starts to melt due to high heat, it can give off poisonous fumes. A plenum-grade cable, however, will not melt in the heat because it is made out of material that is designed for heat-intensive environments. Plenum-grade cabling is much more expensive than PVC, so you should only buy it for cabling that you intend to use in plenum space.

Flexibility: You also need to think about the kind of physical wear-and-tear the cable will be getting. Will the cable sit in plenum space, untouched for most of its existence? Or will the cable spend most of its time in your office drawer, being used for various purposes around the office? Standard core cabling is made out of material that is flexible, which means you can bend it, step on it, and twist it (to a reasonable extent) without breaking it. Solid core cabling, on the other hand, is not so flexible. But its advantage is that it is a better conductor and will transfer data more effectively.

Speed rating: Every Ethernet cable has a speed rating, which defines its max data transfer speed. A cable’s speed rating is usually stamped on the outside of the cable itself. It’s sometimes referred to as a “CAT rating”, since the speed rating begins with the letters “CAT”. The maximum cable length varies between speed ratings, but for most speed ratings it is 100 meters. The ratings are measured in Mbps (megabits per second) or Gbps (gigabytes per second). To get a better feel for how fast this is, I like to divide this number by 8, which tells me how many bytes per second it supports. Note that, in order to take advantage of the full speed a cable offers, all other parts of your network infrastructure must support that speed rating, such as the network cards in the computers and the switches.

Standard Max speed/notes
CAT 1 This is the technical name for a telephone cable! Telephone cables use a RJ-11 connector, whereas Ethernet cables use a RJ-45 connector.
CAT 3 10 Mbps, some variants support 100 Mbps
CAT 5 100 Mbps
CAT 5e 1000 Mbps
CAT 6 1000 Mbps, 10 Gbps (55 meter max cable length)
CAT 6a/e 10 Gbps
CAT 7 10 Gbps with better shielding

Switches

All the computers in an Ethernet network connect to a central device called a switch, which routes the various network data to where it needs to go. This is called a star bus topology—“star” refers to the fact that the computers connect to a central switch (instead of to each other) and “bus” refers to the central device that routes all traffic.

Note that a device called a “bus” can serve as the central device as well, but buses are much more inefficient than switches because they broadcast all messages they receive to all computers, whereas switches only send out messages to the computer that the messages are intended for. Switches used to be more expensive than buses, but not anymore.

To prevent unauthorized computers from connecting to the network, you can disable unused ports on a switch.

Structured Cabling

Larger companies have the money and talent to organize their networks using structured cabling system. The aim of such a system is to create an organized, secure (both from an information safety perspective and a physical safety perspective), and reliable way of connecting all of your company’s computers to each other.

A typical structured cabling system is organized as follows. All cabling, including Ethernet cables and telephone cables, are run from each work area (the office space that an employee occupies) to a central room called the telecommunications room. This cabling is referred to as the horizontal cabling. Each piece of horizontal cabling is referred to as a run. Vocabulary rocks!

In an ideal environment, the horizontal Ethernet cabling would run through plenum space and be of plenum-grade, solid core construction. Each work area would then contain wall outlets that connect to the horizontal cabling. It’s interesting to note that Ethernet wall outlets have CAT ratings as well! Therefore, it’s important to make sure the outlet matches the CAT rating of your horizontal cabling.

The telecommunications room is the central destination for all the horizontal cabling. It contains specially designed equipment racks which are used to store its computer equipment. All rack-mounted equipment adheres to a measurement standard, simply referred to as U, which defines the height of the equipment. 1U equals 1.75 inches. Most rack-mounted equipment is either 1U, 2U, or 4U.

One piece of equipment you’re likely to find in a telecommunications room is a patch panel. A patch panel makes it easy to rearrange your network without having to mess with the horizontal cabling (which often uses fragile, solid core cables). The horizontal cabling is plugged into the back of the patch panel using a connector called a 110 punchdown block. This kind of connector connects the individual wires inside of the Ethernet cable to the patch panel. A punchdown tool is used to attach the cable in this way. Connecting the horizontal cabling to the patch panel is a time consuming process and is meant to be more or less permanent. The other side of the patch panel contains much more flexible RJ-45 ports, which are easy to plug and unplug (kind of like the telephone switches of old). Patch cables are plugged into these ports. Patch cables are short (typically 2-5 feet long), standard core, UTP Ethernet cables. You then use the patch cables to rearrange your network as you like, as often as you like.

SOHO, Bro!

SOHO environments (small office/home office) do not always have the luxury of implementing a structured cabling solution. But there are a number of technologies that you can use to form a LAN without this.

What’s the Wi-Fi password?

The most common and quickest way to create a LAN is to go wireless. Wireless networks are not as fast as wired networks, but for most purposes, they are fast enough. Various wireless standards have been released over the years, each of which varies in speed. In general, they are backwards compatible with each other. Most wireless routers support multiple standards anyway, so you don’t have to worry too much about compatibility most of the time.

Standard Max speed Frequency Range
802.11b 12 Mbps 2.4Ghz 300 feet
802.11a (came out after b) 54 Mbps 5 GHz 150 feet
802.11g 54 Mbps 5 GHz 300 feet
802.11n 100+ Mbps 2.4 & 5 GHz 300+ feet
802.11ac 1 Gbps 5 GHz 300+ feet

Since Wi-Fi transmits its data over the air, securing your Wi-Fi network is of the utmost importance. The latest wireless security protocol is WPA2—all the other standards are vulnerable to security flaws, so you should never use them. Your wireless network should also be password protected, otherwise anyone can connect to it. Another way to secure your network is to configure your router to disable its SSID broadcast, which is what causes your network to appear on a device’s list of available networks. You can also enable MAC address filtering, which only gives pre-approved devices access to the network. Lastly, you should change the router’s administrator password because routers are often all configured with the same administrator password when they leave the factory.

One downside to Wi-Fi is that the wireless signal can be disrupted in many ways. Thick or metallic walls in your building can weaken or stop a wireless signal. Any devices that use the same parts of the wireless spectrum can cause interference as well, such as baby monitors and garage door openers (this is called radio frequency interference or RFI). If you have neighbors that have their own wireless networks, they can interfere with your network too. The parts of your building that get weak or no signal are called dead zones.

Ethernet over Power


If Wi-Fi isn’t an option for your particular environment, you can buy special devices that plug into your electrical outlets which allow you to create an Ethernet network using the electrical wiring of your house! This is called Ethernet over Power (not to be confused with Power over Ethernet, which supplies electrical power through an Ethernet network). This is an example of a bridge because it connects two dissimilar network technologies. Ethernet over Power only supports speeds at around 100Mbps however, so it’s not very fast.

Sunday, June 11, 2017

A Primer on IP Addresses

Just like your have a home address that uniquely identifies your residence out of all the residences in the world, computers have IP addresses, which serve the same purpose.  They uniquely identify a computer in a network so that it can receive messages from other computers.

IPv4

IPv4 was created when the internet was born in 1981 and is still used today.  It is the network communication protocol that computers use to talk to each other over the internet.  An IPv4 address is a unique identifier that is used to identify an individual computer that is connected to the internet.  It is 32-bits long and is commonly represented in dotted-decimal notation.  This notation divides the bits into four, 8-bit chunks and displays each chunk as a number ranging from 0 to 255.  Each number is separated with a dot.  For example: 192.168.2.1.

At its inception, the set of all possible IPv4 addresses, called the address space, was divided into “classes”.  Each class contained a finite number of “chunks” of addresses.  The number of addresses in each chunk varied depending on the class.  The idea was that institutions, such as companies and schools, could purchase one of these chunks, and then dole out the addresses in the chunk to all the computers on their network.  Larger institutions with lots of computers could purchase a more expensive, higher class chunk that had lots of addresses, while smaller institutions that had fewer computers could purchase a cheaper, lower class chunk that had fewer sub addresses.

The classes are summarized below.  If you want to learn more about the logic behind how they were organized, I suggest you read this Wikipedia page.


Class
Number of chunks
Number of addresses in each chunk
Class A
128
16,777,216
Class B
16,384
65,536
Class C
2,097,152
256
Class D
reserved
Class E
reserved

Do you see a problem here?

The problem with this scheme was that companies were unlikely to use every address that was available to them.  The choices for the number of addresses you could have varied wildly—you could have 16,777,216, 65,536, or 256!  You couldn't have anything in between!  If a company needed, say, 1,000 addresses, they had no choice but to purchase a Class B address and put all the rest to waste.  To top it off, some of the organizations that were involved in the early development of the internet possessed Class A chunks, which they were hardly making any use of.

This started to become a pressing issue as the internet grew.  The risk that all IP addresses would be used up, called IP address exhaustion, became a real possibility.

CIDR

As shown, the way the class system divided up its chunks of addresses was very coarse-grained, which resulted in lots of wasted addresses.  To combat this, the class system was done away with in 1993 and replaced with a system called CIDR (Classless Inter-Domain Routing).  This system gives organizations many more choices regarding how many addresses they are assigned, which results in less wasted addresses.

CIDR uses something called variable-length subnet masking (VLSM), which allows the address's subnet mask (the part that identifies which organization an address belongs to) to be of any size.  The class system, on the other hand, only permitted the subnet mask to be 8 bits (Class A), 16 bits (Class B), or 24 bits (Class C) long.  With CIDR, if your company only needed 1,000 addresses, you could purchase a 1,024 chunk (22-bit subnet mask, leaving 10-bits for the address, 2^10=1,024).

CIDR notation consists of an IP address, followed by the number of bits the address uses for its subnet mask.  For example, 192.168.100.14/22 represents the IP address 192.168.100.14 with the first 22 bits of that address being the subnet mask.

But CIDR is only a stop-gap measure.  The IPv4 address space consists of about 4.3 billion addresses, which seems like a lot.  But on a global scale, it is not.  If the internet continues to grow, the IPv4 address space will soon run out.  A more permanent solution would be to increase the length of the IP address.  Enter IPv6.

IPv6

Created in 1998, IPv6 addresses are a whopping 128 bits long, resulting in an incredibly large address space of 3.4 x 10^38 (the number of grains of sand on Earth...or something?).

IPv6 addresses are represented as eight, four character, hexadecimal strings separated by colons.

FEDC:0000:0000:0000:00CF:0000:BA98:1234

Because they are so long, there are tricks you can employ to make them shorter.  If a segment contains all zeroes, you can replace the segment with a single zero:

FEDC:0:0:0:00CF:0:BA98:1234

If an address contains consecutive segments which consist of all zeroes, you can replace them with a double colon (but you can only use this trick once):

FEDC::00CF:0:BA98:1234

And if a segment begins with zeroes, you can leave the zeroes out (unless the segment contains all zeroes, in which case you must leave one zero in):

FEDC::CF:0:BA98:1234

IPv6 and IPv4 are not compatible with each other, which complicates the migration process.  While it is likely that the network card in your computer supports both IPv4 and IPv6, the infrastructure around the globe that makes the internet work cannot switch over so easily.  It will be a long and piecemeal process.  But if all goes well, you won't even know it happened.

Tuesday, June 6, 2017

The Laser Printing Process

There are many different kinds of printers on the market. In office environments, laser printers are by far the most numerous. Not only do they produce good quality printouts, but they are fast, which is important when you have people to please and deadlines to meet. Therefore, computer technicians have to be very familiar with how laser printers work so breakdowns can be fixed and Janet can get her TPS reports on time.

A laser printer follows a specific process when printing a sheet of paper. The process can be divided into seven steps.

1. Processing

In order to start printing, the printer has to first receive print data from a computer. The program the user is printing from (say, a word processor) has to first convert the document to some kind of format the printer understands. Many Windows applications use a system called GDI (graphical device interface), which is used in conjunction with the specific printer driver, to generate this print data.

The application then sends the print data to the print spooler, which is responsible for queuing up print jobs and sending them one at a time to the printer. Once the print job has been completely sent to the printer, it disappears from the print spooler (whether the printer is done printing it or not).

Note that, while it is possible to cancel a print job from the print spooler, this only stops the flow of information from the computer to the printer. For example, if the spooler sends half of the print job before you cancel it, the printer will print exactly that, even if the job is canceled before any pages came out of the printer. Therefore, you should also press the “stop” button on the printer itself to be sure the printing truly stops (do not pull out the paper tray, as this could jam the printer).

2. Charging

The rest of this process is centered around an important part of the printer called the drum. The drum is a cylinder shaped component which is used to transfer images onto the sheets of paper.  It does this using positive and negative electrical charges.

In the Charging step, the primary corona wire (or primary charge roller) gives the drum's surface a uniform negative electrical charge.

3. Exposing

A laser draws a positively charged image into the drum (hence the name, “laser printer”).

4. Developing

Negatively-charged toner particles attach themselves to the positively-charged parts of the drum the laser drew from the last step. "Toner" is the stuff that makes up the image on the piece of paper (it is a laser printer's “ink”).

5. Transferring

Here is where the actual piece of paper comes into play. The transfer corona (or transfer roller) applies a positive charge to a sheet of paper. Then, the negatively-charged toner particles on the drum attach themselves to the positively-charged paper. Voila! The toner has been “transferred” to the page.

6. Fusing

At this point, the toner is simply resting on top of the page like a layer of dust. In the Fusing step, the toner is melted onto the page using a heating element called the fuser (toner is mostly made of plastic). Hot Pockets! The page is now done!

7. Cleaning

Now that the page is done, the printer has to be “reset” for the next page. Notably, the drum must be cleaned. First, any residual toner is scraped off using a rubber cleaning blade. Then, erase lamps give the drum a neutral charge. Go back to step 2.

Thursday, May 15, 2014

5 Things You Might Not Know About Git

Git is a version control system that has gained a lot of popularity over the past few years. It started out as a custom-designed VCS (version control system) for the Linux kernel and has since ballooned in popularity, arguably thanks to Github, a free source code hosting site that is powered by Git. Below are five facts about Git that you might not know:

1. Stashing

This command saves all the uncommitted modifications you've made to your working copy, and then reverts your working copy back to its original state. This is useful if you want to switch branches, but your changes are in an incomplete state and you don't want to commit anything yet (git will not allow you to switch branches if you have uncommitted changes).

The command to run a stash operation is git stash. When you're ready to re-apply your stashed changes, run git stash apply.

You can also create multiple stashes. To see a list of all stashes, run git stash list. By default, when you run git stash apply, it will apply the stash at the top of the list. To apply a different stash, run git stash apply stash@{2} where stash@{2} is the name of the stash as shown in the stash list.

Also note that when you apply a stash, it will remain in the stash list. To delete a stash, run git stash drop. Or, you can run git stash pop to apply a stash and then delete it.

Stashes are only stored in your local repository. They cannot be pushed to remote repositories.

For more information, see: http://git-scm.com/book/en/Git-Tools-Stashing

2. Amending commits

With most other version control systems, if you forgot to include a file in a commit, you have to make a second commit. This is annoying because it makes the commit history longer than it should be. With Git, instead of making a second commit, you can "amend" the previous commit. This will merge your commit in with the previous one.

> git commit --amend

For more information, see: http://git-scm.com/book/en/Git-Basics-Undoing-Things

3. Git is a file system

At its core, Git is actually a key/value data store. The commands that you use on a daily basis, like push and commit, are tools that are built on top of the data store. To demonstrate, I'll show you how to add and retrieve files from a Git repository, without using any of the typical Git commands.

First, initialize an empty repository:

> git init
Initialized empty Git repository in /home/michael/git-blog/.git/

Next, add a file to the repository. This command will return a SHA-1 hash, which we will need to retrieve the file again.

> echo 'file data' | git hash-object -w --stdin 
987721052266a93a2509c3a8ac9e8c86341d0835

Then, retrieve the file like so:

> git cat-file -p 987721052266a93a2509c3a8ac9e8c86341d0835
file data

For more information, see: http://git-scm.com/book/en/Git-Internals-Git-Objects

4. Commit message templates

If you work in a corporate environment, your team might have a policy on how commit messages have to be formatted. Git allows you to define a file that contains the default commit message to use for all commits.

> git config --global commit.template path/to/commit-message.txt

For more information, see: http://git-scm.com/book/en/Customizing-Git-Git-Configuration

5. Ignoring files during export

Git includes a command that lets you easily generate an archive file (.zip, .tar, etc) of your project. By default, all files in your project are included, but there may be some files which you want to exclude. To do this, use the export-ignore attribute:

> echo "test/ export-ignore" > .gitattributes
> git add .gitattributes
> git commit -m "Added .gitattributes file."
> git archive -o latest.zip HEAD

For more information, see: http://git-scm.com/book/en/Customizing-Git-Git-Attributes

Thursday, May 1, 2014

Presenter First: An Overview

Writing GUI applications can be difficult. It's easier to understand the flow of a command-line program--you start at the top and go to the bottom. But the flow of a GUI application, with its listeners, event handlers, and callbacks, goes all over the place. Add database queries and network calls to the mix, and things get even more complicated.

Enter MVP

The Model-View-Presenter (MVP) pattern helps to manage this complexity. MVP belongs to that family of design patterns that separates the application data and logic from the way in which the information is displayed to the user. To summarize:

  • The Model is responsible for maintaining the application's raw data (typically by persisting it in a database).
  • The View is responsible for presenting the data to the user (for example, in the form of a webpage or dialog box).
  • And the Presenter is responsible for tying the model and view together. In MVP, the model and view know nothing of each other!

Presenter First

The idea with "Presenter First" is that, using the MVP pattern, you start by writing the presenter class before anything else. This forces you to think abstractly about how your dialog window is going to behave. And, in the process of writing the presenter, you naturally figure out what functionalities the model and view will need to support. So, writing the model and view becomes just a matter of implementing an interface.

Another benefit to Presenter First is that it allows you to unit test your dialog's application logic. This is because the model and view are represented as interfaces, which can be easily mocked-out in the unit tests.

To summarize, the three benefits of Presenter First are:

  1. By using MVP, the view is cleanly separated from the application data and logic. In other words, your JFrame and JDialog classes become truly "dumb"--they contain no database calls or application logic.
  2. In the process of writing the presenter, the APIs for the model and view are essentially written automatically.
  3. The application logic of your dialog is finally unit-testable!

Example

As an example, let's create a simple login dialog. This dialog will ask the user for a username and password. If the credentials are valid, then a session token will be returned and the dialog will close. The user can also choose to have the application remember his username and password.

We start by writing the presenter class.

LoginPresenter.java

import java.awt.event.*;

public class LoginPresenter{
    private final ILoginView view;
    private final ILoginModel model;

    public LoginPresenter(ILoginView view, ILoginModel model){
        this.view = view;
        this.model = model;

        //invoked when the user clicks "Login"
        view.addLoginListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent event){
                onLogin();
            }
        });

        //invoked when the user clicks "Cancel" or closes the window
        view.addCancelListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent event){
                onCancel();
            }
        });

        //populate the dialog with its initial data
        view.setUsername(model.getCachedUsername());
        view.setPassword(model.getCachedPassword());
        view.setRememberMe(model.getCachedRememberMe());

        //finally, display the dialog
        view.display();
    }

    private void onLogin(){
        //get the data that the user entered
        String username = view.getUsername();
        String password = view.getPassword();
        boolean rememberMe = view.getRememberMe();

        //send the network call to log the user in
        String session = model.login(username, password);

        if (session == null){
            //credentials were bad, so show an error dialog to the user
            view.onBadLogin();
            return;
        }

        //persist the login credentials if "remember me" is checked
        if (rememberMe){
           model.setCachedUsername(username);
           model.setCachedPassword(password);
        } else {
           model.setCachedUsername("");
           model.setCachedPassword("");
        }

        model.setCachedRememberMe(rememberMe);
        model.setSession(session);

        view.onSuccessfulLogin();
        view.close();
    }

    private void onCancel(){
        view.close();
    }
}

The constructor adds event handlers which will fire with the user presses the "Login" and "Cancel" buttons. Then, it populates the view with data from the model (in this case, the saved username and password). The "onLogin()" method contains logic which determines if the login was successful or not and acts accordingly.

Now that our presenter is written, we can write the model and view interfaces, which allows the presenter class to compile.

ILoginModel.java

public interface ILoginModel{
    String login(String username, String password);

    String getCachedUsername();
    void setCachedUsername(String username);
    String getCachedPassword();
    void setCachedPassword(String password);
    boolean getCachedRememberMe();
    void setCachedRememberMe(boolean rememberMe);
    String getSession();
    void setSession(String session);
}

ILoginView.java

import java.awt.event.*;

public interface ILoginView{
    void addLoginListener(ActionListener listener);
    void addCancelListener(ActionListener listener);

    String getUsername();
    void setUsername(String username);
    String getPassword();
    void setPassword(String password);
    boolean getRememberMe();
    void setRememberMe(boolean rememberMe);

    void onBadLogin();
    void onSuccessfulLogin();

    void display();
    void close();
}

Next, we write our tests! Using a stubbing framework like Mockito helps, but it's not required (you could always create your own test implementations of the model and view interfaces).

LoginPresenterTest.java

import java.awt.event.*;
import java.util.*;
import org.junit.*;
import org.mockito.invocation.*;
import org.mockito.stubbing.*;
import static org.mockito.Mockito.*;

public class LoginPresenterTest{
    @Test
    public void init(){
        ILoginView view = mock(ILoginView.class);

        ILoginModel model = mock(ILoginModel.class);
        when(model.getCachedUsername()).thenReturn("user");
        when(model.getCachedPassword()).thenReturn("password");
        when(model.getCachedRememberMe()).thenReturn(true);

        LoginPresenter presenter = new LoginPresenter(view, model);

        verify(view).addLoginListener(any(ActionListener.class));
        verify(view).addCancelListener(any(ActionListener.class));
        verify(view).setUsername("user");
        verify(view).setPassword("password");
        verify(view).setRememberMe(true);
        verify(view).display();
    }

    @Test
    public void bad_login(){
        ILoginView view = mock(ILoginView.class);
        when(view.getUsername()).thenReturn("user");
        when(view.getPassword()).thenReturn("password");
        ListenerAnswer loginAnswer = new ListenerAnswer();
        doAnswer(loginAnswer).when(view).addLoginListener(any(ActionListener.class));

        ILoginModel model = mock(ILoginModel.class);
        when(model.login("user", "password")).thenReturn(null); //"null" = bad login

        LoginPresenter presenter = new LoginPresenter(view, model);

        //click "login"
        loginAnswer.fire();

        verify(model, never()).setSession(anyString());
        verify(view, never()).onSuccessfulLogin();
        verify(view).onBadLogin();
        verify(view, never()).close();
    }

    @Test
    public void valid_login(){
        ILoginView view = mock(ILoginView.class);
        when(view.getUsername()).thenReturn("user");
        when(view.getPassword()).thenReturn("password");
        ListenerAnswer loginAnswer = new ListenerAnswer();
        doAnswer(loginAnswer).when(view).addLoginListener(any(ActionListener.class));

        ILoginModel model = mock(ILoginModel.class);
        when(model.login("user", "password")).thenReturn("abc123"); //non-null token = good login

        LoginPresenter presenter = new LoginPresenter(view, model);

        //click "login"
        loginAnswer.fire();

        verify(model).setSession("abc123");
        verify(view, never()).onBadLogin();
        verify(view).onSuccessfulLogin();
        verify(view).close();
    }

    @Test
    public void rememberMe_true(){
        ILoginView view = mock(ILoginView.class);
        when(view.getUsername()).thenReturn("user");
        when(view.getPassword()).thenReturn("password");
        when(view.getRememberMe()).thenReturn(true);
        ListenerAnswer loginAnswer = new ListenerAnswer();
        doAnswer(loginAnswer).when(view).addLoginListener(any(ActionListener.class));

        ILoginModel model = mock(ILoginModel.class);
        when(model.login("user", "password")).thenReturn("abc123");

        LoginPresenter presenter = new LoginPresenter(view, model);

        //click "login"
        loginAnswer.fire();

        verify(model).setCachedUsername("user");
        verify(model).setCachedPassword("password");
        verify(model).setCachedRememberMe(true);
    }

    @Test
    public void rememberMe_false(){
        ILoginView view = mock(ILoginView.class);
        when(view.getUsername()).thenReturn("user");
        when(view.getPassword()).thenReturn("password");
        when(view.getRememberMe()).thenReturn(false);
        ListenerAnswer loginAnswer = new ListenerAnswer();
        doAnswer(loginAnswer).when(view).addLoginListener(any(ActionListener.class));

        ILoginModel model = mock(ILoginModel.class);
        when(model.login("user", "password")).thenReturn("abc123");

        LoginPresenter presenter = new LoginPresenter(view, model);

        //click "login"
        loginAnswer.fire();

        verify(model).setCachedUsername("");
        verify(model).setCachedPassword("");
        verify(model).setCachedRememberMe(false);
    }

    @Test
    public void cancel(){
        ILoginView view = mock(ILoginView.class);
        ListenerAnswer cancelAnswer = new ListenerAnswer();
        doAnswer(cancelAnswer).when(view).addCancelListener(any(ActionListener.class));

        ILoginModel model = mock(ILoginModel.class);

        LoginPresenter presenter = new LoginPresenter(view, model);

        //click "cancel"
        cancelAnswer.fire();

        verify(model, never()).setSession(anyString());
        verify(view).close();
    }

    private class ListenerAnswer implements Answer<Object>{
        private final List<ActionListener> listeners = new ArrayList<ActionListener>();

        public Object answer(InvocationOnMock invocation) {
            ActionListener listener = (ActionListener)invocation.getArguments()[0];
            listeners.add(listener);
            return null;
        }

        public void fire(){
            for (ActionListener listener : listeners){
                listener.actionPerformed(null);
            }
        }
    }
}

Once our tests pass, we can write the real implementations of the model and view interfaces. Again, this is basically just a matter of creating a new class and having that class implement the interface.

LoginViewImpl.java

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import static javax.swing.SpringLayout.*;

public class LoginViewImpl extends JFrame implements ILoginView {
    private final JButton login, cancel;
    private final JTextField username;
    private final JPasswordField password;
    private final JCheckBox rememberMe;

    public LoginViewImpl() {
        setTitle("Login");
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

        login = new JButton("Login");
        cancel = new JButton("Cancel");
        username = new JTextField();
        password = new JPasswordField();
        rememberMe = new JCheckBox("Remember me");

        JLabel title = new JLabel("Please enter your login credentials.");
        JLabel usernameLabel = new JLabel("Username:");
        JLabel passwordLabel = new JLabel("Password:");

        ///////////////////////

        Container contentPane = getContentPane();
        SpringLayout layout = new SpringLayout();
        contentPane.setLayout(layout);

        contentPane.add(title);
        contentPane.add(usernameLabel);
        contentPane.add(username);
        contentPane.add(passwordLabel);
        contentPane.add(password);
        contentPane.add(rememberMe);
        contentPane.add(login);
        contentPane.add(cancel);

        layout.putConstraint(WEST, title, 5, WEST, contentPane);
        layout.putConstraint(NORTH, title, 5, NORTH, contentPane);

        layout.putConstraint(WEST, usernameLabel, 5, WEST, contentPane);
        layout.putConstraint(NORTH, usernameLabel, 10, SOUTH, title);
        layout.putConstraint(WEST, username, 10, EAST, usernameLabel);
        layout.putConstraint(NORTH, username, 0, NORTH, usernameLabel);
        layout.putConstraint(EAST, username, 100, WEST, username);

        layout.putConstraint(WEST, passwordLabel, 5, WEST, contentPane);
        layout.putConstraint(NORTH, passwordLabel, 5, SOUTH, usernameLabel);
        layout.putConstraint(WEST, password, 0, WEST, username);
        layout.putConstraint(NORTH, password, 0, NORTH, passwordLabel);
        layout.putConstraint(EAST, password, 100, WEST, password);

        layout.putConstraint(WEST, rememberMe, 5, WEST, contentPane);
        layout.putConstraint(NORTH, rememberMe, 5, SOUTH, passwordLabel);

        layout.putConstraint(WEST, login, 5, WEST, contentPane);
        layout.putConstraint(NORTH, login, 10, SOUTH, rememberMe);
        layout.putConstraint(WEST, cancel, 5, EAST, login);
        layout.putConstraint(NORTH, cancel, 0, NORTH, login);

        setSize(300,200);
        setLocationRelativeTo(null);
    }

    public void addLoginListener(ActionListener listener) {
        login.addActionListener(listener);
        username.addActionListener(listener);
        password.addActionListener(listener);
    }

    public void addCancelListener(final ActionListener listener) {
        cancel.addActionListener(listener);
        addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent event){
                listener.actionPerformed(null);
            }
        });
    }

    public String getUsername() {
        return username.getText();
    }

    public void setUsername(String username) {
        this.username.setText(username);
    }

    public String getPassword() {
        return new String(password.getPassword());
    }

    public void setPassword(String password){
        this.password.setText(password);
    }

    public boolean getRememberMe() {
        return rememberMe.isSelected();
    }

    public void setRememberMe(boolean rememberMe) {
        this.rememberMe.setSelected(rememberMe);
    }

    public void onBadLogin() {
        JOptionPane.showMessageDialog(this, "Invalid login credentials.");
    }

    public void onSuccessfulLogin() {
        JOptionPane.showMessageDialog(this, "Login successful.");
    }

    public void display() {
        setVisible(true);
    }

    public void close() {
        dispose();
    }
}

LoginModelImpl.java

import java.io.*;
import java.util.*;

public class LoginModelImpl implements ILoginModel{
    private final File file;
    private final Properties properties;
    private String session;

    public LoginModelImpl(File file) throws IOException{
        this.file = file;
        this.properties = new Properties();

        if (file.exists()){
            this.properties.load(new FileReader(file));
        }
    }

    public String login(String username, String password){
        //normally, a network or database call would be made here
        if ("test".equals(username) && "test".equals(password)){
            return "abc123";
        }
        return null;
    }

    public String getCachedUsername(){
        return properties.getProperty("username");
    }

    public void setCachedUsername(String username){
        properties.setProperty("username", username);
        save();
    }

    public String getCachedPassword(){
        return properties.getProperty("password");
    }

    public void setCachedPassword(String password){
        properties.setProperty("password", password);
        save();
    }

    public boolean getCachedRememberMe(){
        String value = properties.getProperty("rememberMe");
        return (value == null) ? false : Boolean.parseBoolean(value);
    }

    public void setCachedRememberMe(boolean rememberMe){
        properties.setProperty("rememberMe", rememberMe + "");
        save();
    }

    public String getSession(){
        return session;
    }

    public void setSession(String session){
        this.session = session;
    }

    private void save() {
        try {
            properties.store(new FileWriter(file), "");
        } catch (IOException e){
            throw new RuntimeException(e);
        }
    }
}

To run our program, we simply create a new instance of LoginPresenter, passing in the model and view implementations that we created above.

Main.java

import java.io.*;

public class Main{
    public static void main(String args[]) throws Throwable {
        File cache = new File("cache.properties");

        ILoginModel model = new LoginModelImpl(cache);
        ILoginView view = new LoginViewImpl();
        new LoginPresenter(view, model);
    }
}

And that's all there is to it!

Download the source code

References:

Saturday, September 7, 2013

Adding syntax highlighting to Javadocs

Often times, when writing Javadocs, it helps to include source code samples along with the documentation. Typically, this is achieved by inserting the source code into a <pre> tag. This will render the code in a monospaced font when viewed in a browser.

/**
 * <p>Represents a fruit.</p>
 * <pre>
 * //create a new fruit
 * Fruit fruit = new Fruit("banana");
 *
 * //copy an existing fruit
 * Fruit copy = new Fruit(fruit);
 * </pre>
 * @author John Doe
 */
public class Fruit{
  ...
}

But there tools out there that can add syntax highlighting to source code on a web page. Javadocs are a webpage. Why can't these syntax highlighting tools be applied to Javadocs as well?

In this blog post, I am going to show you how to add syntax highlighting to a Maven-enabled Java project. I will be using the popular Javascript-based SyntaxHighlighter library for the syntax highlighting.

1. Download SyntaxHighligher

First, download SyntaxHighlighter.

2. Create a CSS file

SyntaxHighlighter makes use of CSS styling to perform the code coloring. Luckily, the Javadoc tool allows you to specify a CSS file to customize the look and feel of your Javadoc webpage. So, we will need to create a CSS file that contains the styling that SyntaxHighlighter requires.

Navigate to the SyntaxHighlighter files that you downloaded in the previous step. In the "styles" directory, locate the "shCore.css" file and one of the "shTheme" files (such as "shThemeDefault.css", see: all the available themes). Combine these two files into a single file and give it a name of your choosing. Save this file somewhere within your project folder. The location doesn't matter, since Javadoc will end up copying the file when the Javadocs are generated. A good place is the "src/main/javadoc" folder, as this is the standard Maven location for all Javadoc-related resources.

3. Configure your POM file

Next, we will need to add some configuration settings to the project POM. In the configuration section of the "maven-javadoc-plugin" plugin, add the following: (1) the location of the CSS file that was created in the previous step, (2) <script> tags for the SyntaxHighlighter Javascript files, and (3) Javascript code to configure and initialize SyntaxHighlighter.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-javadoc-plugin</artifactId>
  <version>2.8.1</version>
  <configuration>

    <!-- (1) CSS file location -->
    <stylesheetfile>src/main/javadoc/syntax-highlighter.css</stylesheetfile>

    <!-- (2) SyntaxHighlighter Javascript files -->
    <top><![CDATA[
      <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript"></script>
      <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js" type="text/javascript"></script>
    ]]></top>

    <!--
    (3) SyntaxHighlighter configuration and initialization
    See: http://alexgorbatchev.com/SyntaxHighlighter/manual/configuration/
    -->
    <footer><![CDATA[
      <script type="text/javascript">
        SyntaxHighlighter.defaults["auto-links"] = false;
        SyntaxHighlighter.defaults["tab-size"] = 2;
        SyntaxHighlighter.all();
      </script>
    ]]></footer>

  </configuration>
</plugin>

A list of available SyntaxHighlighter configuration settings can be found on the SyntaxHighlighter homepage.

4. Modify the Javadocs

Each <pre> tag in the Javadocs must be given a class="brush:java" attribute. This signals to SyntaxHighlighter that the text content should be treated as Java source code.

/**
 * <p>Represents a fruit.</p>
 * <pre class="brush:java">
 * //create a new fruit
 * Fruit fruit = new Fruit("banana");
 *
 * //copy an existing fruit
 * Fruit copy = new Fruit(fruit);
 * </pre>
 * @author John Doe
 */
public class Fruit{
  ...
}

5. Generate the Javadocs

Instruct Maven to generate the Javadocs for the project by running the following command:

mvn javadoc:javadoc

And that's it! You should be good to go.

References: