create a method that accepts an IOException as an
DAOFactory.java
DAOFactory.java
public
class
DAOFactory
{
// this method maps the ProductDAO interface
// to the appropriate data storage mechanism
public
static
ProductDAO
getProductDAO
()
{
ProductDAO
pDAO
=
new
ProductTextFile
();
return
pDAO
;
}
}
IOStringUtils.java
IOStringUtils.java
import
java
.
io
.
*
;
public
class
IOStringUtils
{
public
static
void
writeFixedString
(
DataOutput
out
,
int
length
,
String
s
)
throws
IOException
{
for
(
int
i
=
0
;
i
<
length
;
i
++
)
{
if
(
i
<
s
.
length
())
out
.
writeChar
(
s
.
charAt
(
i
));
// write char
else
out
.
writeChar
(
0
);
// write Unicode zero
}
}
public
static
String
readFixedString
(
DataInput
in
,
int
length
)
throws
IOException
{
StringBuilder
sb
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
length
;
i
++
)
{
char
c
=
in
.
readChar
();
// if char is not Unicode zero add to string
if
(
c
!=
0
)
sb
.
append
(
c
);
}
return
sb
.
toString
();
}
}
Product.java
Product.java
import
java
.
text
.
NumberFormat
;
public
class
Product
{
private
String
code
;
private
String
description
;
private
double
price
;
public
Product
()
{
this
(
""
,
""
,
0
);
}
public
Product
(
String
code
,
String
description
,
double
price
)
{
this
.
code
=
code
;
this
.
description
=
description
;
this
.
price
=
price
;
}
public
void
setCode
(
String
code
)
{
this
.
code
=
code
;
}
public
String
getCode
(){
return
code
;
}
public
void
setDescription
(
String
description
)
{
this
.
description
=
description
;
}
public
String
getDescription
()
{
return
description
;
}
public
void
setPrice
(
double
price
)
{
this
.
price
=
price
;
}
public
double
getPrice
()
{
return
price
;
}
public
String
getFormattedPrice
()
{
NumberFormat
currency
=
NumberFormat
.
getCurrencyInstance
();
return
currency
.
format
(
price
);
}
public
boolean
equals
(
Object
object
)
{
if
(
object
instanceof
Product
)
{
Product
product2
=
(
Product
)
object
;
if
(
code
.
equals
(
product2
.
getCode
())
&&
description
.
equals
(
product2
.
getDescription
())
&&
price
==
product2
.
getPrice
()
)
return
true
;
}
return
false
;
}
public
String
toString
()
{
return
"Code: "
+
code
+
"\n"
+
"Description: "
+
description
+
"\n"
+
"Price: "
+
this
.
getFormattedPrice
()
+
"\n"
;
}
}
ProductConstants.java
ProductConstants.java
public
interface
ProductConstants
{
int
CODE_SIZE
=
4
;
int
DESCRIPTION_SIZE
=
40
;
}
ProductDAO.java
ProductDAO.java
public
interface
ProductDAO
extends
ProductReader
,
ProductWriter
,
ProductConstants
{
// all methods from the ProductReader and ProductWriter interfaces
// all static constants from the ProductConstants interface
}
ProductMaintApp.java
ProductMaintApp.java
import
java
.
util
.
Scanner
;
import
java
.
util
.
ArrayList
;
public
class
ProductMaintApp
implements
ProductConstants
{
// declare two class variables
private
static
ProductDAO
productDAO
=
null
;
private
static
Scanner
sc
=
null
;
public
static
void
main
(
String
args
[])
{
// display a welcome message
System
.
out
.
println
(
"Welcome to the Product Maintenance application\n"
);
// set the class variables
productDAO
=
DAOFactory
.
getProductDAO
();
sc
=
new
Scanner
(
System
.
in
);
// display the command menu
displayMenu
();
// perform 1 or more actions
String
action
=
""
;
while
(
!
action
.
equalsIgnoreCase
(
"exit"
))
{
// get the input from the user
action
=
Validator
.
getString
(
sc
,
"Enter a command: "
);
System
.
out
.
println
();
if
(
action
.
equalsIgnoreCase
(
"list"
))
displayAllProducts
();
else
if
(
action
.
equalsIgnoreCase
(
"add"
))
addProduct
();
else
if
(
action
.
equalsIgnoreCase
(
"del"
)
||
action
.
equalsIgnoreCase
(
"delete"
))
deleteProduct
();
else
if
(
action
.
equalsIgnoreCase
(
"help"
)
||
action
.
equalsIgnoreCase
(
"menu"
))
displayMenu
();
else
if
(
action
.
equalsIgnoreCase
(
"exit"
)
||
action
.
equalsIgnoreCase
(
"quit"
))
System
.
out
.
println
(
"Bye.\n"
);
else
System
.
out
.
println
(
"Error! Not a valid command.\n"
);
}
}
public
static
void
displayMenu
()
{
System
.
out
.
println
(
"COMMAND MENU"
);
System
.
out
.
println
(
"list - List all products"
);
System
.
out
.
println
(
"add - Add a product"
);
System
.
out
.
println
(
"del - Delete a product"
);
System
.
out
.
println
(
"help - Show this menu"
);
System
.
out
.
println
(
"exit - Exit this application\n"
);
}
public
static
void
displayAllProducts
()
{
System
.
out
.
println
(
"PRODUCT LIST"
);
ArrayList
<
Product
>
products
=
productDAO
.
getProducts
();
Product
p
=
null
;
StringBuilder
sb
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
products
.
size
();
i
++
)
{
p
=
products
.
get
(
i
);
sb
.
append
(
StringUtils
.
padWithSpaces
(
p
.
getCode
(),
CODE_SIZE
+
4
));
sb
.
append
(
StringUtils
.
padWithSpaces
(
p
.
getDescription
(),
DESCRIPTION_SIZE
+
4
));
sb
.
append
(
p
.
getFormattedPrice
());
sb
.
append
(
"\n"
);
}
System
.
out
.
println
(
sb
.
toString
());
}
public
static
void
addProduct
()
{
String
code
=
Validator
.
getString
(
sc
,
"Enter product code: "
);
String
description
=
Validator
.
getLine
(
sc
,
"Enter product description: "
);
double
price
=
Validator
.
getDouble
(
sc
,
"Enter price: "
);
Product
product
=
new
Product
();
product
.
setCode
(
code
);
product
.
setDescription
(
description
);
product
.
setPrice
(
price
);
productDAO
.
addProduct
(
product
);
System
.
out
.
println
();
System
.
out
.
println
(
description
+
" has been added.\n"
);
}
public
static
void
deleteProduct
()
{
String
code
=
Validator
.
getString
(
sc
,
"Enter product code to delete: "
);
Product
p
=
productDAO
.
getProduct
(
code
);
System
.
out
.
println
();
if
(
p
!=
null
)
{
productDAO
.
deleteProduct
(
p
);
System
.
out
.
println
(
p
.
getDescription
()
+
" has been deleted.\n"
);
}
else
{
System
.
out
.
println
(
"No product matches that code.\n"
);
}
}
}
ProductRandomFile.java
ProductRandomFile.java
import
java
.
io
.
*
;
import
java
.
util
.
*
;
public
class
ProductRandomFile
implements
ProductDAO
{
private
RandomAccessFile
productsFile
=
null
;
private
ArrayList
<
String
>
productCodes
=
null
;
private
final
int
PRICE_SIZE
=
8
;
// doubles are 8 bytes
private
final
int
RECORD_SIZE
=
CODE_SIZE
*
2
+
// from the ProductConstants interface
DESCRIPTION_SIZE
*
2
+
// from the ProductConstants interface
PRICE_SIZE
;
private
final
String
DELETION_CODE
=
" "
;
public
ProductRandomFile
()
{
try
{
productsFile
=
new
RandomAccessFile
(
"products.ran"
,
"rw"
);
productCodes
=
this
.
getCodes
();
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
e
);
}
}
//*************************************************
// Private methods for reading products
//*************************************************
private
int
getRecordCount
()
throws
IOException
{
int
recordCount
=
(
int
)
productsFile
.
length
()
/
RECORD_SIZE
;
return
recordCount
;
}
private
int
getRecordNumber
(
String
productCode
)
{
for
(
int
i
=
0
;
i
<
productCodes
.
size
();
i
++
)
{
String
code
=
productCodes
.
get
(
i
);
if
(
productCode
.
equals
(
code
))
return
i
;
}
return
-
1
;
// no record matches the product code
}
private
Product
getRecord
(
int
recordNumber
)
throws
IOException
{
if
(
recordNumber
>=
0
&&
recordNumber
<
this
.
getRecordCount
())
{
productsFile
.
seek
(
recordNumber
*
RECORD_SIZE
);
String
code
=
IOStringUtils
.
readFixedString
(
productsFile
,
CODE_SIZE
);
String
description
=
IOStringUtils
.
readFixedString
(
productsFile
,
DESCRIPTION_SIZE
);
double
price
=
productsFile
.
readDouble
();
Product
product
=
new
Product
(
code
,
description
,
price
);
return
product
;
}
else
{
return
null
;
}
}
private
ArrayList
<
String
>
getCodes
()
{
try
{
ArrayList
<
String
>
codes
=
new
ArrayList
<>
();
for
(
int
i
=
0
;
i
<
getRecordCount
();
i
++
)
{
productsFile
.
seek
(
i
*
RECORD_SIZE
);
codes
.
add
(
IOStringUtils
.
readFixedString
(
productsFile
,
CODE_SIZE
));
}
return
codes
;
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
e
);
return
null
;
}
}
//*********************************************************
// Public methods for reading products
//*********************************************************
public
ArrayList
<
Product
>
getProducts
()
{
ArrayList
<
Product
>
products
=
new
ArrayList
<>
();
try
{
for
(
int
i
=
0
;
i
<
productCodes
.
size
();
i
++
)
{
// if record has been marked for deletion,
// don't add to products array list
if
(
!
productCodes
.
get
(
i
).
equals
(
DELETION_CODE
))
{
Product
product
=
this
.
getRecord
(
i
);
products
.
add
(
product
);
}
}
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
e
);
return
null
;
}
return
products
;
}
public
Product
getProduct
(
String
productCode
)
{
try
{
int
recordNumber
=
this
.
getRecordNumber
(
productCode
);
Product
product
=
this
.
getRecord
(
recordNumber
);
return
product
;
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
e
);
return
null
;
}
}
//*************************************************
//* Private methods for writing products
//*************************************************
private
boolean
writeProduct
(
Product
product
,
int
recordNumber
)
{
try
{
productsFile
.
seek
(
recordNumber
*
RECORD_SIZE
);
IOStringUtils
.
writeFixedString
(
productsFile
,
CODE_SIZE
,
product
.
getCode
());
IOStringUtils
.
writeFixedString
(
productsFile
,
DESCRIPTION_SIZE
,
product
.
getDescription
());
productsFile
.
writeDouble
(
product
.
getPrice
());
return
true
;
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
e
);
return
false
;
}
}
//*************************************************
//* Public methods for writing products
//*************************************************
public
boolean
addProduct
(
Product
product
)
{
productCodes
.
add
(
product
.
getCode
());
int
recordNumber
=
getRecordNumber
(
product
.
getCode
());
return
writeProduct
(
product
,
recordNumber
);
}
public
boolean
updateProduct
(
Product
product
)
{
int
recordNumber
=
getRecordNumber
(
product
.
getCode
());
if
(
recordNumber
!=
-
1
)
return
writeProduct
(
product
,
recordNumber
);
else
return
false
;
}
public
boolean
deleteProduct
(
Product
product
)
{
int
recordNumber
=
getRecordNumber
(
product
.
getCode
());
if
(
recordNumber
!=
-
1
)
{
productCodes
.
set
(
recordNumber
,
DELETION_CODE
);
product
.
setCode
(
DELETION_CODE
);
// mark record for deletion
return
writeProduct
(
product
,
recordNumber
);
}
else
{
return
false
;
}
}
}
ProductReader.java
ProductReader.java
import
java
.
util
.
ArrayList
;
public
interface
ProductReader
{
Product
getProduct
(
String
code
);
ArrayList
<
Product
>
getProducts
();
}
ProductTextFile.java
ProductTextFile.java
import
java
.
util
.
*
;
import
java
.
io
.
*
;
import
java
.
nio
.
file
.
*
;
public
final
class
ProductTextFile
implements
ProductDAO
{
private
ArrayList
<
Product
>
products
=
null
;
private
Path
productsPath
=
null
;
private
File
productsFile
=
null
;
private
final
String
FIELD_SEP
=
"\t"
;
public
ProductTextFile
()
{
productsPath
=
Paths
.
get
(
"products.txt"
);
productsFile
=
productsPath
.
toFile
();
products
=
this
.
getProducts
();
}
public
ArrayList
<
Product
>
getProducts
()
{
// if the products file has already been read, don't read it again
if
(
products
!=
null
)
return
products
;
products
=
new
ArrayList
<>
();
if
(
Files
.
exists
(
productsPath
))
// prevent the FileNotFoundException
{
try
{
// open the input stream
BufferedReader
in
=
new
BufferedReader
(
new
FileReader
(
productsFile
));
// read all products stored in the file
// into the array list
String
line
=
in
.
readLine
();
while
(
line
!=
null
)
{
String
[]
columns
=
line
.
split
(
FIELD_SEP
);
String
code
=
columns
[
0
];
String
description
=
columns
[
1
];
String
price
=
columns
[
2
];
Product
p
=
new
Product
(
code
,
description
,
Double
.
parseDouble
(
price
));
products
.
add
(
p
);
line
=
in
.
readLine
();
}
// close the input stream
in
.
close
();
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
e
);
return
null
;
}
}
return
products
;
}
public
Product
getProduct
(
String
code
)
{
for
(
Product
p
:
products
)
{
if
(
p
.
getCode
().
equals
(
code
))
return
p
;
}
return
null
;
}
public
boolean
addProduct
(
Product
p
)
{
products
.
add
(
p
);
return
this
.
saveProducts
();
}
public
boolean
deleteProduct
(
Product
p
)
{
products
.
remove
(
p
);
return
this
.
saveProducts
();
}
public
boolean
updateProduct
(
Product
newProduct
)
{
// get the old product and remove it
Product
oldProduct
=
this
.
getProduct
(
newProduct
.
getCode
());
int
i
=
products
.
indexOf
(
oldProduct
);
products
.
remove
(
i
);
// add the updated product
products
.
add
(
i
,
newProduct
);
return
this
.
saveProducts
();
}
private
boolean
saveProducts
()
{
try
{
// open the output stream
PrintWriter
out
=
new
PrintWriter
(
new
BufferedWriter
(
new
FileWriter
(
productsFile
)));
// write all products in the array list
// to the file
for
(
Product
p
:
products
)
{
out
.
print
(
p
.
getCode
()
+
FIELD_SEP
);
out
.
print
(
p
.
getDescription
()
+
FIELD_SEP
);
out
.
println
(
p
.
getPrice
());
}
// close the output stream
out
.
close
();
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
e
);
return
false
;
}
return
true
;
}
}
ProductWriter.java
ProductWriter.java
public
interface
ProductWriter
{
boolean
addProduct
(
Product
p
);
boolean
updateProduct
(
Product
p
);
boolean
deleteProduct
(
Product
p
);
}
StringUtils.java
StringUtils.java
public
class
StringUtils
{
public
static
String
padWithSpaces
(
String
s
,
int
length
)
{
if
(
s
.
length
()
<
length
)
{
StringBuilder
sb
=
new
StringBuilder
(
s
);
while
(
sb
.
length
()
<
length
)
{
sb
.
append
(
" "
);
}
return
sb
.
toString
();
}
else
{
return
s
.
substring
(
0
,
length
);
}
}
}
Validator.java
Validator.java
import
java
.
util
.
Scanner
;
public
class
Validator
{
public
static
String
getLine
(
Scanner
sc
,
String
prompt
)
{
System
.
out
.
print
(
prompt
);
String
s
=
sc
.
nextLine
();
// read the whole line
return
s
;
}
public
static
String
getString
(
Scanner
sc
,
String
prompt
)
{
System
.
out
.
print
(
prompt
);
String
s
=
sc
.
next
();
// read the first string on the line
sc
.
nextLine
();
// discard the rest of the line
return
s
;
}
public
static
int
getInt
(
Scanner
sc
,
String
prompt
)
{
boolean
isValid
=
false
;
int
i
=
0
;
while
(
isValid
==
false
)
{
System
.
out
.
print
(
prompt
);
if
(
sc
.
hasNextInt
())
{
i
=
sc
.
nextInt
();
isValid
=
true
;
}
else
{
System
.
out
.
println
(
"Error! Invalid integer value. Try again."
);
}
sc
.
nextLine
();
// discard any other data entered on the line
}
return
i
;
}
public
static
int
getInt
(
Scanner
sc
,
String
prompt
,
int
min
,
int
max
)
{
int
i
=
0
;
boolean
isValid
=
false
;
while
(
isValid
==
false
)
{
i
=
getInt
(
sc
,
prompt
);
if
(
i
<=
min
)
System
.
out
.
println
(
"Error! Number must be greater than "
+
min
);
else
if
(
i
>=
max
)
System
.
out
.
println
(
"Error! Number must be less than "
+
max
);
else
isValid
=
true
;
}
return
i
;
}
public
static
double
getDouble
(
Scanner
sc
,
String
prompt
)
{
boolean
isValid
=
false
;
double
d
=
0
;
while
(
isValid
==
false
)
{
System
.
out
.
print
(
prompt
);
if
(
sc
.
hasNextDouble
())
{
d
=
sc
.
nextDouble
();
isValid
=
true
;
}
else
{
System
.
out
.
println
(
"Error! Invalid decimal value. Try again."
);
}
sc
.
nextLine
();
// discard any other data entered on the line
}
return
d
;
}
public
static
double
getDouble
(
Scanner
sc
,
String
prompt
,
double
min
,
double
max
)
{
double
d
=
0
;
boolean
isValid
=
false
;
while
(
isValid
==
false
)
{
d
=
getDouble
(
sc
,
prompt
);
if
(
d
<=
min
)
System
.
out
.
println
(
"Error! Number must be greater than "
+
min
);
else
if
(
d
>=
max
)
System
.
out
.
println
(
"Error! Number must be less than "
+
max
);
else
isValid
=
true
;
}
return
d
;
}
}