
Тестування програми
Для організації зручності тестування усі вхідні дані записуються у файл, оскільки у класі що забезпечує це читання (DeclarationReader) вхідний потік з якого здійснюється читання є вхідним параметром, переключатись між зчитуванням інформації з консолі і з файлу досить легко для клієнта класу. Тестування XSD схеми проводилось шляхом введення не правильних даних до XML файлу, будь-яка з таких не вірних змін викликала виключення при запуску методу валідації, що означає що схема правильно підключена, а також працює правильно. Крім того, під час тестування для різних наборів вхідних даних серіалізований об’єкт завжди дорівнював десеріалізованому.
ВИСНОВОК
Розроблена програма призначена для відтворення множини витрат та підрахунку податків з кожного, а також занесення \ зчитування інформації у XML файл відповідає усім пунктам технічного завдання, а також для реалізації використовує лише стандартні засоби мови програмування Java. Крім того, хоча й існує велика кількість бібліотек що беруть на себе майже всю можливу роботу по серіалізації та десеріалізації об’єктів, проте створені у програмі класи є зручної обгорткою вище названих класів, та дають клієнту можливість більш просто виконувати ці ж операції для класів доходів.
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ
Г. Шилдт «Полное руководство – издательский дом «ВИЛЬЯМС» - ISBN: 978-58459-1759-1
Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес Приемы объетктно-ориентированого проектирования. Паттерны проектирования – СПб «Питер», 2007. С. 366 – ISBN 978-5-469-011136-1.
The Java Tutorials are practical guides for programmers http://docs.oracle.com/javase/tutorial/
JavaTM 2 Platform, Standard Edition, v 1.4.2 API Specification http://docs.oracle.com/javase/1.4.2/docs/api/
Questions on Java http://stackoverflow.com/questions/
Шаблони проектування програмного забезпечення – http://uk.wikipedia.org/wiki/Шаблони проектування програмного забезпечення
XML Schema Structures Second Edition http://www.w3.org/TR/xmlschema-1/
Introduction to XML Schema http://www.w3schools.com/schema/schema_intro.asp
Додаток 1. UML Діаграма пакету edu.kpi.profit
Додаток 2. UML Діаграма пакету edu.kpi.menu
Додаток 3. UML Діаграма пакету edu.kpi.menu
Додаток 4. UML Діаграма пакету edu.kpi.XML
Додаток
5. Документація - пакети програми
Додаток
6. Документація – пакет edu.kpi.declaration
Додаток
7. Документація – пакет edu.kpi.menu
Додаток 8. Документація – пакет edu.kpi.profit
Додаток
9. Документація – пакет edu.kpi.XML
Додаток 10. Документація – внепакетні класи
Додаток 11. Отриманий XML файл
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<declaration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="dec-2324121">
<profits xsi:type="profitPropertySale">
<income>10000.3</income>
<tax>0.0</tax>
<propertyType>OTHER</propertyType>
<isResident>true</isResident>
</profits>
<profits xsi:type="profitGift">
<income>1000.0</income>
<tax>0.0</tax>
<giftType>PRECIOUS_METALS</giftType>
<isResident>false</isResident>
<isCloseRelative>true</isCloseRelative>
</profits>
<profits xsi:type="profitGift">
<income>300.0</income>
<tax>0.0</tax>
<giftType>CURRENCY</giftType>
<isResident>true</isResident>
<isCloseRelative>false</isCloseRelative>
</profits>
<profits xsi:type="profitHonorar">
<income>100.0</income>
<tax>30.000002</tax>
<workType>ARTIST</workType>
</profits>
<profits xsi:type="profitGift">
<income>1000.33</income>
<tax>50.016502</tax>
<giftType>REALTY</giftType>
<isResident>false</isResident>
<isCloseRelative>false</isCloseRelative>
</profits>
<profits xsi:type="profitSubJob">
<income>1000.0</income>
<tax>150.0</tax>
</profits>
<profits xsi:type="profitMaterialAid">
<income>1000.0</income>
<tax>150.0</tax>
<aidType>ENTOMBMENT</aidType>
</profits>
<profits xsi:type="profitPropertySale">
<income>1220.0</income>
<tax>183.0</tax>
<propertyType>OTHER</propertyType>
<isResident>false</isResident>
</profits>
<profits xsi:type="profitChildrenAid">
<income>3000.0</income>
<tax>210.0</tax>
<salary>3000.0</salary>
</profits>
<profits xsi:type="profitMainJob">
<income>2500.0</income>
<tax>375.0</tax>
</profits>
<profits xsi:type="profitMainJob">
<income>3300.35</income>
<tax>495.05252</tax>
</profits>
<profits xsi:type="profitRemittance">
<income>10000.0</income>
<tax>1500.0</tax>
</profits>
</declaration>
Додаток 12. XSD Схема
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:element name="declaration">
<xs:complexType>
<xs:sequence>
<xs:element name="profits" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="id" type="xs:ID" use="required"/>
</xs:complexType>
</xs:element>
<xs:complexType name="profit" abstract="true">
<xs:sequence>
<xs:element name="income" type="nonNegativeDecimal"/>
<xs:element name="tax" type="nonNegativeDecimal"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="profitChildrenAid">
<xs:complexContent>
<xs:extension base="profit">
<xs:sequence>
<xs:element name="salary" type="nonNegativeDecimal"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="profitGift">
<xs:complexContent>
<xs:extension base="profit">
<xs:sequence>
<xs:element name="giftType" type="giftType"/>
<xs:element name="isResident" type="xs:boolean"/>
<xs:element name="isCloseRelative" type="xs:boolean"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="profitHonorar">
<xs:complexContent>
<xs:extension base="profit">
<xs:sequence>
<xs:element name="workType" type="workType"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="profitMainJob">
<xs:complexContent>
<xs:extension base="profit"/>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="profitMaterialAid">
<xs:complexContent>
<xs:extension base="profit">
<xs:sequence>
<xs:element name="aidType" type="aidType"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="profitPropertySale">
<xs:complexContent>
<xs:extension base="profit">
<xs:sequence>
<xs:element name="propertyType" type="propertyType"/>
<xs:element name="isResident" type="xs:boolean"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="profitRemittance">
<xs:complexContent>
<xs:extension base="profit"/>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="profitSubJob">
<xs:complexContent>
<xs:extension base="profit"/>
</xs:complexContent>
</xs:complexType>
<xs:simpleType name="giftType">
<xs:restriction base="xs:string">
<xs:enumeration value="REALTY"/>
<xs:enumeration value="CURRENCY"/>
<xs:enumeration value="PRECIOUS_METALS"/>
<xs:enumeration value="SECURITIES"/>
<xs:enumeration value="OTHER"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="workType">
<xs:restriction base="xs:string">
<xs:enumeration value="LITERATURE"/>
<xs:enumeration value="ARTIST"/>
<xs:enumeration value="OTHER"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="aidType">
<xs:restriction base="xs:string">
<xs:enumeration value="MEDICAL_SERVICE"/>
<xs:enumeration value="ENTOMBMENT"/>
<xs:enumeration value="DISABLED"/>
<xs:enumeration value="REHABILITATION"/>
<xs:enumeration value="OTHER"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="propertyType">
<xs:restriction base="xs:string">
<xs:enumeration value="APARTMENT"/>
<xs:enumeration value="FLAT"/>
<xs:enumeration value="ROOM"/>
<xs:enumeration value="GARDEN_HOUSE"/>
<xs:enumeration value="OTHER"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="nonNegativeDecimal">
<xs:restriction base="xs:decimal">
<xs:minInclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
Додаток 13. Сирцевий код програмного додатку
Main
import edu.kpi.XML.XMLReader;
import edu.kpi.XML.XMLWriter;
import edu.kpi.declaration.Declaration;
public class Main {
private static String InFile = "declaration.in";
private static String XMLFile = "declaration.xml";
private static String XSDSchema = "declaration.xsd";
public static void main(String[] args){
try{
Declaration declaration = DeclarationReader.read(InFile);
declaration.SortProfitsByTax();
/* edu.kpi.XMLWriter. This is not the default one class */
XMLWriter.write(XMLFile, XSDSchema, declaration);
/* edu.kpi.XMLReader. This is not the default one class */
XMLReader xmlReader = new XMLReader();
Declaration resultDeclaration = xmlReader.read(XMLFile, XSDSchema);
if(resultDeclaration==null)
System.out.println("Файл не був валідований!");
else
System.out.println("Файл успішно зчитаний.");
}catch(Exception e){
e.printStackTrace();
}
}
}
DeclarationReader
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Scanner;
import edu.kpi.declaration.Declaration;
import edu.kpi.menu.*;
import edu.kpi.menu.MenuItemValueRead.ValueType;
import edu.kpi.profit.*;
import edu.kpi.profit.ProfitGift.GiftType;
import edu.kpi.profit.ProfitHonorar.WorkType;
import edu.kpi.profit.ProfitMaterialAid.AidType;
import edu.kpi.profit.ProfitPropertySale.PropertyType;
/**
* This class organizes reading information
* from the specified source and creating the
* declaration class by using methods from MenuItem
* abstract class subclasses.
*
* This class contains only static methods.
*
* @see MenuItem
*/
public class DeclarationReader {
/** Console menu tree */
private static final MenuItem myMenu =
new MenuItemChoose(
"Виберіть що додати до декларації:",
new MenuItem[]{
new MenuItemStepShow(
"1. Доходи з основного місця роботи",
new MenuItem[]{
new MenuItemValueRead(
"Введіть заробітну плату:", ValueType.FLOAT)
}
),
new MenuItemStepShow(
"2. Доходи з додаткового місця роботи",
new MenuItem[]{
new MenuItemValueRead(
"Введіть заробітну плату:",ValueType.FLOAT)
}
),
new MenuItemStepShow(
"3. Авторська винагорода",
new MenuItem[]{
new MenuItemValueRead(
"Введіть розмір гонорару:",ValueType.FLOAT),
new MenuItemValueRead(
"Виберіть тип роботи:\n" +
"1. Літературна робота\n" +
"2. Художньо графічна робота\n"+
"3. Інше\n",ValueType.INTEGER,3),
}
),
new MenuItemStepShow(
"4. Продаж майна",
new MenuItem[]{
new MenuItemValueRead(
"Введіть оціночну вартість:",ValueType.FLOAT),
new MenuItemValueRead(
"Виберіть тип властності:\n" +
"1. Жилий дім\n" +
"2. Квартира\n" +
"3. Кімната\n" +
"4. Садовий дім\n" +
"5. Інше\n",ValueType.INTEGER,5),
new MenuItemValueRead(
"Ви є резидентом?\n" +
"1. Так\n" +
"2. Ні\n",ValueType.INTEGER,2)
}
),
new MenuItemStepShow(
"5. Отримання в подарунок грошей і майна",
new MenuItem[]{
new MenuItemValueRead(
"Введіть вартість подарунку:",ValueType.FLOAT),
new MenuItemValueRead(
"Виберіть тип подарунку:\n" +
"1. Нерухомість\n" +
"2. Валюта\n" +
"3. Цінні метали\n" +
"4. Цінні папери\n" +
"5. Інше\n",ValueType.INTEGER,5),
new MenuItemValueRead(
"Ви є резидентом?\n" +
"1. Так\n" +
"2. Ні\n",ValueType.INTEGER,2),
new MenuItemValueRead(
"Дарувач родич першого порядку?\n" +
"1. Так\n" +
"2. Ні\n",ValueType.INTEGER,2)
}
),
new MenuItemStepShow(
"6. Отримання переводів з-за кордону",
new MenuItem[]{
new MenuItemValueRead(
"Введіть суму переводу",ValueType.FLOAT)
}
),
new MenuItemStepShow(
"7. Отримання допомоги дітей",
new MenuItem[]{
new MenuItemValueRead(
"Введіть розмір допомоги",ValueType.FLOAT),
new MenuItemValueRead(
"Введіть вашу сумарну заробітну плату",ValueType.FLOAT)
}
),
new MenuItemStepShow(
"8. Отримання матеріальної допомоги",
new MenuItem[]{
new MenuItemValueRead(
"Введіть розмір матеріальної допомоги",ValueType.FLOAT),
new MenuItemValueRead(
"Виберіть тип матерільної допомоги:\n" +
"1. На лікування\n" +
"2. Допомога на погребіння\n" +
"3. Непрацездатним\n" +
"4. На реабілітація після лікування\n" +
"5. Інше\n",ValueType.INTEGER,5),
}
)
}
);
public static Declaration read(InputStream source){
Scanner scanner = new Scanner(source);
myMenu.setInputStream(scanner);
System.out.println("Введіть номер декларації:");
Declaration declaration = new Declaration(readPositiveInteger(scanner));
float[] result;
int choice;
do
{
result = myMenu.show();
choice = myMenu.getChosenItem();
if(choice!=0)
declaration.addProfit(ChooseProfitInstance(choice,result));
}while(choice!=0);
scanner.close();
return declaration;
}
public static Declaration read(String filename) throws FileNotFoundException{
return read(new FileInputStream(filename));
}
private static Profit ChooseProfitInstance(int choice,float[] result){
switch(choice){
case 1:
return new ProfitMainJob(result[0]);
case 2:
return new ProfitSubJob(result[0]);
case 3:
return new ProfitHonorar(result[0],WorkType.values()[(int)result[1]-1]);
case 4:
return new ProfitPropertySale(result[0],PropertyType.values()[(int)result[1]-1],bool(result[2]));
case 5:
return new ProfitGift(result[0],GiftType.values()[(int)result[1]-1],bool(result[2]),bool(result[3]));
case 6:
return new ProfitRemittance(result[0]);
case 7:
return new ProfitChildrenAid(result[0],result[1]);
case 8:
return new ProfitMaterialAid(result[0],AidType.values()[(int)result[1]-1]);
}
return null;
}
private static boolean bool(float value){
return (value==1) ? true : false;
}
private static int readPositiveInteger(Scanner sc)
{
boolean valid;
String inputLine;
do
{
inputLine = sc.nextLine();
if(!(valid = inputLine.matches("\\d+")))
System.out.println("Невірний ввід!");
}while(!valid);
return Integer.parseInt(inputLine);
}
}
edu.kpi.declaration.Declaration
package edu.kpi.declaration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import edu.kpi.profit.Profit;
/**
* This class is holder of collection of
* profit abstract class subclasses.
* Also this class has functionality
* for sorting this collection by tax.
*
* @see Profit
*/
@XmlRootElement(namespace="")
public class Declaration {
@XmlElement
private ArrayList<Profit> profits = new ArrayList<Profit>();
@XmlAttribute
private String id;
/** Empty constructor for JABX. Setting it to private to block access for other clients*/
@SuppressWarnings("unused")
private Declaration(){}
public Declaration(int id){
this.id = "dec-"+Integer.toString(id);
}
public void addProfit(Profit profit) {
profits.add(profit);
}
public void addAll(Collection<? extends Profit> c) {
profits.addAll(c);
}
public void addAll(Profit[] profitsArr){
for(int i=0;i<profitsArr.length;i++)
profits.add(profitsArr[i]);
}
public void SortProfitsByTax(){
Collections.sort(profits, new TaxComparator());
}
public Profit[] getProfits() {
// Size = 0, let toArray method find it's size for us
Profit[] arr = new Profit[0];
arr = profits.toArray(arr);
return arr;
}
}
edu.kpi.declaration.package-info
/**
*
* @author Empower
*
*/
@XmlSchema(
xmlns = {
@XmlNs(namespaceURI = "http://www.w3.org/2001/XMLSchema-instance", prefix = "xsi"),
},
location = "",
namespace = "http://www.w3.org/2001/XMLSchema-instance",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.UNQUALIFIED)
package edu.kpi.declaration;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.XmlNs;
edu.kpi.declaration.TaxComparator
package edu.kpi.declaration;
import java.util.Comparator;
import edu.kpi.profit.Profit;
/**
* Comparing Profit class subclasses
* by tax parameter.
*
* @see Profit
*/
public class TaxComparator implements Comparator<Profit>{
@Override
public int compare(Profit a, Profit b) {
Float aTax = a.getTax();
Float bTax = b.getTax();
return aTax.compareTo(bTax);
}
}
edu.kpi.menu.MenuItem
package edu.kpi.menu;
import java.util.Scanner;
/**
* This class contains the menu item and
* it's possible sub menus also it
* has some simple methods
* for handling user menu navigating
* commands.
*
* It's subclasses realizes 3
* menu items behaviors
* on choosing by user by
* overriding execute abstract method.
*
* @see MenuItemChoose
* @see MenuItemStepShow
* @see MenuItemValueRead
*/
public abstract class MenuItem{
protected String text;
protected MenuItem[] childMenus;
protected static float[] info;
protected static int chosenItem;
protected static int currHandled;
private static Scanner sc;
protected final static String exitString = "\n0. Вихід";
private final static String errorMessage = "Невірний ввід!";
public MenuItem(String text,MenuItem[] childMenus){
this.text = text;
this.childMenus = childMenus;
}
public MenuItem(String text){
this(text,null);
}
public void setInputStream(Scanner scanner){
sc = scanner;
}
public int getChosenItem(){
return chosenItem;
}
public float[] show(){
info = new float[4];
currHandled = 0;
execute();
return info;
}
protected int readInteger(Integer maxValid, boolean allowZero)
{
boolean valid;
String inputLine;
do
{
inputLine = sc.nextLine();
valid = inputLine.matches("\\d") && (maxValid==null ||
Integer.parseInt(inputLine)<=maxValid) &&
(allowZero || Integer.parseInt(inputLine)!=0);
if(!valid)
System.out.println(errorMessage);
}while(!valid);
return Integer.parseInt(inputLine);
}
protected float readFloat()
{
boolean valid;
String inputLine;
do
{
inputLine = sc.nextLine();
if(!(valid = inputLine.matches("\\d+(\\.\\d+)?") &&
Float.parseFloat(inputLine)!=0))
System.out.println(errorMessage);
}while(!valid);
return Float.parseFloat(inputLine);
}
protected abstract void execute();
}
edu.kpi.menu.MenuItemChoose
package edu.kpi.menu;
/**
* This MenuItem subclass is
* menu item that is "waiting" for
* user input to execute one of
* it's children.
*
* @see MenuItem
*/
public class MenuItemChoose extends MenuItem {
public MenuItemChoose(String text, MenuItem[] childMenus) {
super(text, childMenus);
}
@Override
protected void execute() {
System.out.println(text+"\n");
for(int i=0;i<childMenus.length;i++)
System.out.println(childMenus[i].text);
System.out.println(exitString);
chosenItem = readInteger(childMenus.length,true);
if(chosenItem!=0)
childMenus[chosenItem-1].execute();
}
}
edu.kpi.menu.MenuItemStepShow
package edu.kpi.menu;
/**
* This MenuItem subclass is
* menu item which is showing
* its children menus one after
* another.
*
* @see MenuItem
*/
public class MenuItemStepShow extends MenuItem {
public MenuItemStepShow(String text, MenuItem[] childMenus) {
super(text, childMenus);
}
@Override
protected void execute() {
for(int i=0;i<childMenus.length;i++)
childMenus[i].execute();
}
}
edu.kpi.menu.MenuItemValueRead
package edu.kpi.menu;
/**
* This MenuItem subclass is
* a dialog for reading users
* input values. Which are
* basically the result of
* work of whole menu tree.
*
* The class is intended to be
* a final stage (a leaf) of
* the tree which means it is not
* executing any other menu items.
*
* @see MenuItem
*/
public class MenuItemValueRead extends MenuItem {
public enum ValueType {FLOAT, INTEGER};
private ValueType valueType;
private Integer maxValue;
public MenuItemValueRead(String text,ValueType valueType,Integer maxValue) {
super(text);
this.valueType = valueType;
this.maxValue = maxValue;
}
public MenuItemValueRead(String text,ValueType valueType) {
this(text,valueType,null);
}
@Override
protected void execute() {
System.out.println(text);
info[currHandled++] = (valueType==ValueType.FLOAT) ? readFloat(): readInteger(maxValue,false);
}
}
edu.kpi.profit.Profit
package edu.kpi.profit;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSeeAlso;
/**
* This class is an abstract superclass
* for all the profits intended to the
* program. The common things
* for them like income variable
* and abstract getTax method are taken
*
* @see ProfitChildrenAid
* @see ProfitGift
* @see ProfitHonorar
* @see ProfitMainJob
* @see ProfitMaterialAid
* @see ProfitPropertySale
* @see ProfitRemittance
* @see ProfitSubJob
*/
@XmlSeeAlso({ProfitChildrenAid.class,ProfitGift.class,Profit.class,ProfitHonorar.class,
ProfitMainJob.class,ProfitMaterialAid.class,ProfitPropertySale.class,ProfitRemittance.class,ProfitSubJob.class})
public abstract class Profit {
@XmlElement
protected float income;
protected final static int MINIMAL_SALARY = 1176;
public Profit(float income) {
if(income<0)
throw new IllegalArgumentException("Прибуток має бути невід'ємним числом!");
this.income = income;
}
@XmlElement
public abstract float getTax();
}
edu.kpi.profit.ProfitChildrenAid
package edu.kpi.profit;
import javax.xml.bind.annotation.XmlElement;
/**
* This class realizes children aid
* profit and the way it taxed:
*
* 0%, if salary of client is lower
* then minimal salary multiplied
* by 1.4, otherwise - 7%.
*
* @see Profit
*/
public class ProfitChildrenAid extends Profit{
@XmlElement
private float salary;
private final static float SALARY_MULTIPLAYER = 1.4f;
public ProfitChildrenAid(float income, float salary) {
super(income);
if(salary<0)
throw new IllegalArgumentException("Зарплата має бути невід'ємний числом!");
this.salary = salary;
}
@Override
public float getTax() {
float percent;
if(salary<=SALARY_MULTIPLAYER*MINIMAL_SALARY)
percent = 0;
else
percent = 0.07f;
return percent*income;
}
}
edu.kpi.profit.ProfitGift
package edu.kpi.profit;
import javax.xml.bind.annotation.XmlElement;
/**
* This class realizes a profit
* received as a gift and way it
* is taxed. The tax calculated
* by such a principle:
*
* 0% - if the presenter is a relative
* 5% - if he is living or the country
* 15% - otherwise
*
* @see Profit
*/
public class ProfitGift extends Profit {
public enum GiftType {REALTY, CURRENCY, PRECIOUS_METALS, SECURITIES, OTHER};
@XmlElement
private GiftType giftType;
@XmlElement
private boolean isResident;
@XmlElement
private boolean isCloseRelative;
private static final int MIN_TAXED_SUM = 850;
public ProfitGift(float income, GiftType giftType, boolean isResident, boolean isCloseRelative) {
super(income);
this.giftType = giftType;
this.isResident = isResident;
this.isCloseRelative = isCloseRelative;
}
@Override
public float getTax() {
float percent;
if(isCloseRelative || giftType==GiftType.OTHER || giftType!=GiftType.REALTY && income<=MIN_TAXED_SUM)
percent = 0;
else if(!isResident)
percent = 0.05f;
else
percent = 0.15f;
return percent*income;
}
}
edu.kpi.profit.ProfitHonorar
package edu.kpi.profit;
import javax.xml.bind.annotation.XmlElement;
/**
* This class realizes a profit
* received from a honorar and the
* way it is taxed.
*
* Only two types of honorars are taxed:
* honorars for literature works (20%)
* and artist works (30%).
*
* @see Profit
*/
public class ProfitHonorar extends Profit{
public enum WorkType {LITERATURE, ARTIST, OTHER};
@XmlElement
private WorkType workType;
public ProfitHonorar(float income,WorkType workType) {
super(income);
this.workType = workType;
}
@Override
public float getTax() {
float percent;
if(workType==WorkType.LITERATURE)
percent = 0.2f;
else if(workType==WorkType.ARTIST)
percent = 0.3f;
else
percent = 0;
return percent*income;
}
}
edu.kpi.profit.ProfitMainJob
package edu.kpi.profit;
/**
* This class is a representation
* of profit received from the
* main job and the way it is taxed.
*
* 17% - if the salary is 10 times bigger
* than the minimal one.
* 15% - in other cases.
*
* @see Profit
*/
public class ProfitMainJob extends Profit{
private final static int SALARY_MULTIPLAYER = 10;
public ProfitMainJob(float income) {
super(income);
}
@Override
public float getTax() {
float percent;
if(income>SALARY_MULTIPLAYER*MINIMAL_SALARY)
percent = 0.17f;
else
percent = 0.15f;
return percent*income;
}
}
edu.kpi.profit.ProfitMaterialAid
package edu.kpi.profit;
import javax.xml.bind.annotation.XmlElement;
/**
* This is a class of a profit
* from a material aid and the way
* it is taxed.
*
* 17% - if the salary is 10 times bigger
* than the minimal one.
* 15% - in other cases.
*
* @see Profit
*/
public class ProfitMaterialAid extends Profit{
public enum AidType {MEDICAL_SERVICE, ENTOMBMENT, DISABLED, REHABILITATION, OTHER};
@XmlElement
private AidType aidType;
private final static float taxPercent[] = {0.05f, 0.15f, 0.03f, 0.07f, 0.0f};
public ProfitMaterialAid(float income,AidType aidType) {
super(income);
this.aidType = aidType;
}
@Override
public float getTax() {
float percent = taxPercent[aidType.ordinal()];
return percent*income;
}
}
edu.kpi.profit.ProfitPropertySale
package edu.kpi.profit;
import javax.xml.bind.annotation.XmlElement;
/**
* This class represents a profit from
* property sale, and the way it is taxed:
*
* 15% tax if person selling is not liver
* of the country,
* 5% tax if we are selling one of these
* objects:
* - Apartment
* - Flat
* - Room
* - Garden house
* 0% tax otherwise
*
* @see Profit
*/
public class ProfitPropertySale extends Profit{
public enum PropertyType {APARTMENT, FLAT, ROOM, GARDEN_HOUSE, OTHER};
@XmlElement
private PropertyType propertyType;
@XmlElement
private boolean isResident;
public ProfitPropertySale(float income,PropertyType propertyType,boolean isResident) {
super(income);
this.propertyType = propertyType;
this.isResident = isResident;
}
@Override
public float getTax() {
float percent;
if(!isResident)
percent = 0.15f;
else if(propertyType != PropertyType.OTHER)
percent = 0.5f;
else
percent = 0;
return percent*income;
}
}
edu.kpi.profit.ProfitRemittance
package edu.kpi.profit;
/**
* This class represents a profit
* from a foreign payment (remittance)
* and the way it is taxed:
*
* 17% tax if its size is 10 times bigger
* than the minimal salary.
* 15% tax in other cases.
*
*/
public class ProfitRemittance extends Profit{
private final static int SALARY_MULTIPLAYER = 10;
public ProfitRemittance(float income) {
super(income);
}
@Override
public float getTax() {
float percent;
if(income>SALARY_MULTIPLAYER*MINIMAL_SALARY)
percent = 0.17f;
else
percent = 0.15f;
return percent*income;
}
}
edu.kpi.profit.ProfitSubJob
package edu.kpi.profit;
/**
* This class is a representation
* of profit received from the
* sub job and the way it is taxed.
*
* Tax percent is constant here
* it is 15%.
*
* @see Profit
*/
public class ProfitSubJob extends Profit{
public ProfitSubJob(float income) {
super(income);
}
@Override
public float getTax() {
return 0.15f*income;
}
}
edu.kpi.XML.ElementHandler
package edu.kpi.XML;
import java.util.ArrayList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import edu.kpi.declaration.Declaration;
/**
* This class is intended to handle messages
* sent from SaxParser. Basically it "tells"
* XMLReader how to create declaration and profit
* instances depending on the messages received from
* the parser.
*
* This class is designed to be accessed only by
* XMLReader and XMLWriter classes (the constructor
* has only package visibility).
*
* @see Declaration
* @see Profit
*/
class ElementHandler extends DefaultHandler{
private XMLReader reader;
private Boolean isTax = false;
private ArrayList<String> arguments = new ArrayList<String>();
ElementHandler(XMLReader reader) {
this.reader = reader;
}
public void startElement(String uri, String local_name, String raw_name, Attributes amap) throws SAXException {
switch(raw_name){
case "declaration":
reader.startDeclaration(amap.getValue(1));
break;
case "profits":
reader.startProfit(amap.getValue(0));
break;
case "tax":
isTax = true;
break;
}
}
public void endElement(String uri, String local_name, String raw_name) throws SAXException {
switch(raw_name){
case "profits":
reader.endProfit(arguments);
arguments.clear();
break;
case "tax":
isTax = false;
break;
}
}
public void characters(char[] ch, int start, int length) throws SAXException {
String value = new String(ch,start,length);
if (!Character.isISOControl(value.charAt(0)) && !isTax) {
arguments.add(value);
}
}
}
edu.kpi.XML.XMLReader
package edu.kpi.XML;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.xml.sax.SAXException;
import edu.kpi.declaration.Declaration;
import edu.kpi.profit.*;
import edu.kpi.profit.ProfitGift.GiftType;
import edu.kpi.profit.ProfitHonorar.WorkType;
import edu.kpi.profit.ProfitMaterialAid.AidType;
import edu.kpi.profit.ProfitPropertySale.PropertyType;
/**
* This class is for reading XML
* files written by edu.kpi.XMLWriter
* class, which are resenting
* Declaration class instances.
*
* The XML parser type used
* here is SAX parser.
*
* Before reading the XML it is being
* validated by specified XSD schema.
*
* @see Declaration
*/
public class XMLReader {
private Declaration declaration;
private String profitType;
public Declaration read(String filename, String schema) throws ParserConfigurationException, SAXException, IOException{
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
if(!validate(filename, schema))
return null;
parser.parse(new File(filename), new ElementHandler(this));
return declaration;
}
void startDeclaration(String decId){
int id = Integer.parseInt(decId.substring(4));
declaration = new Declaration(id);
}
void startProfit(String type){
profitType = type;
}
void endProfit(ArrayList<String> values)
{
Profit toAdd = getProfitInstance(values);
declaration.addProfit(toAdd);
}
private boolean validate(String filename,String schemaName) throws IOException, SAXException{
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(new File(schemaName));
Validator validator = schema.newValidator();
StreamSource source = new StreamSource(filename);
try {
validator.validate(source);
} catch (SAXException e) {
return false;
}
return true;
}
private Profit getProfitInstance(ArrayList<String> values){
switch(profitType){
case "profitMainJob":
return new ProfitMainJob(Float.parseFloat(values.get(0)));
case "profitSubJob":
return new ProfitSubJob(Float.parseFloat(values.get(0)));
case "profitHonorar":
return new ProfitHonorar(Float.parseFloat(values.get(0)),WorkType.valueOf(values.get(1)));
case "profitPropertySale":
return new ProfitPropertySale(Float.parseFloat(values.get(0)),PropertyType.valueOf(values.get(1)),bool(values.get(2)));
case "profitGift":
return new ProfitGift(Float.parseFloat(values.get(0)),GiftType.valueOf(values.get(1)),bool(values.get(2)),bool(values.get(3)));
case "profitRemittance":
return new ProfitRemittance(Float.parseFloat(values.get(0)));
case "profitChildrenAid":
return new ProfitChildrenAid(Float.parseFloat(values.get(0)),Float.parseFloat(values.get(1)));
case "profitMaterialAid":
return new ProfitMaterialAid(Float.parseFloat(values.get(0)),AidType.valueOf(values.get(1)));
}
return null;
}
private boolean bool(String value){
return (value.equals("true")) ? true : false;
}
}
edu.kpi.XML.XMLWriter
package edu.kpi.XML;
import java.io.File;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.xml.sax.SAXException;
import edu.kpi.declaration.Declaration;
/**
* This class writes declaration
* class instances to specified file.
*
* The methods from javax.xml.bind
* library classes are used for
* these actions.
*
* @see Declaration
*/
public class XMLWriter {
public static void write(String dest, String schemaFile, Declaration declaration) throws SAXException,JAXBException{
JAXBContext context = JAXBContext.newInstance(declaration.getClass());
Marshaller m = context.createMarshaller();
// for line indentation, new line delimiters
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.setSchema(createShema(schemaFile));
try{
m.marshal( declaration, new File(dest));
}
catch(JAXBException e){
throw new JAXBException("Документ не пройшов валідацію!");
}
}
private static Schema createShema(String filename) throws SAXException{
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
return schemaFactory.newSchema(new File(filename));
}
}