Initial commit
This commit is contained in:
commit
3d28766fb5
22 changed files with 2062 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Project exclude paths
|
||||
/.gradle/
|
||||
/build/
|
||||
/build/classes/java/main/
|
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
6
.idea/compiler.xml
Normal file
6
.idea/compiler.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="11" />
|
||||
</component>
|
||||
</project>
|
17
.idea/gradle.xml
Normal file
17
.idea/gradle.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
20
.idea/jarRepositories.xml
Normal file
20
.idea/jarRepositories.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
10
.idea/misc.xml
Normal file
10
.idea/misc.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
124
.idea/uiDesigner.xml
Normal file
124
.idea/uiDesigner.xml
Normal file
|
@ -0,0 +1,124 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
37
build.gradle.kts
Normal file
37
build.gradle.kts
Normal file
|
@ -0,0 +1,37 @@
|
|||
plugins {
|
||||
java
|
||||
}
|
||||
|
||||
group = "ru.erius"
|
||||
version = "1.0"
|
||||
val mainClass = "$group.${name.toLowerCase()}.$name"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
|
||||
}
|
||||
|
||||
tasks.getByName<Test>("test") {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
manifest {
|
||||
attributes(
|
||||
"Manifest-Version" to "1.0",
|
||||
"Main-Class" to mainClass
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.javadoc {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
185
gradlew
vendored
Normal file
185
gradlew
vendored
Normal file
|
@ -0,0 +1,185 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MSYS* | MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
89
gradlew.bat
vendored
Normal file
89
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,89 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
2
settings.gradle.kts
Normal file
2
settings.gradle.kts
Normal file
|
@ -0,0 +1,2 @@
|
|||
rootProject.name = "Lab5"
|
||||
|
18
src/main/java/ru/erius/lab5/Lab5.java
Normal file
18
src/main/java/ru/erius/lab5/Lab5.java
Normal file
|
@ -0,0 +1,18 @@
|
|||
package ru.erius.lab5;
|
||||
|
||||
import ru.erius.lab5.cli.CommandParser;
|
||||
import ru.erius.lab5.collection.PersonTreeSet;
|
||||
|
||||
public class Lab5 {
|
||||
/**
|
||||
* Создание коллекции {@link PersonTreeSet PersonTreeSet}
|
||||
* и парсера {@link CommandParser CommandParser}, запуск программы на выполнение
|
||||
*
|
||||
* @param args Аргументы командной строки
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
PersonTreeSet pts = new PersonTreeSet();
|
||||
CommandParser cmd = new CommandParser(pts);
|
||||
cmd.start();
|
||||
}
|
||||
}
|
597
src/main/java/ru/erius/lab5/cli/CommandParser.java
Normal file
597
src/main/java/ru/erius/lab5/cli/CommandParser.java
Normal file
|
@ -0,0 +1,597 @@
|
|||
package ru.erius.lab5.cli;
|
||||
|
||||
import ru.erius.lab5.collection.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Класс, добавляющий возможность интерактивного взаимодействия пользователя с коллекцией через терминал,
|
||||
* для своей работы требует экземпляр класса {@link PersonTreeSet PersonTreeSet}
|
||||
*/
|
||||
public class CommandParser {
|
||||
/**
|
||||
* Вспомогательная строка для создания красивого вывода
|
||||
*/
|
||||
private final static String LINE = "=============================================================================================================================================================================================";
|
||||
/**
|
||||
* Строка, выводимая при запуске программы
|
||||
*/
|
||||
private final static String GREETINGS = LINE + "\n" +
|
||||
"Добро пожаловать в программу для управления коллекцией объектов в интерактивном режиме!\n" +
|
||||
"Напишите help, чтобы увидеть доступные команды\n" +
|
||||
"Напишите exit, чтобы выйти из программы\n" +
|
||||
LINE + "\n";
|
||||
/**
|
||||
* Строка, выводимая при написании команды help
|
||||
*/
|
||||
private final static String HELP = LINE + "\n" +
|
||||
"help: вывести справку по доступным командам\n" +
|
||||
"info : вывести в стандартный поток вывода информацию о коллекции (тип, дата инициализации, количество элементов и т.д.)\n" +
|
||||
"show : вывести в стандартный поток вывода все элементы коллекции в строковом представлении\n" +
|
||||
"add [element] : добавить новый элемент в коллекцию\n" +
|
||||
"update {id} [element] : обновить значение элемента коллекции, id которого равен заданному\n" +
|
||||
"remove_by_id {id} : удалить элемент из коллекции по его id\n" +
|
||||
"clear : очистить коллекцию\n" +
|
||||
"save : сохранить коллекцию в файл\n" +
|
||||
"execute_script {file_name} : считать и исполнить скрипт из указанного файла. В скрипте содержатся команды в таком же виде, в котором их вводит пользователь в интерактивном режиме.\n" +
|
||||
"exit : завершить программу (без сохранения в файл)\n" +
|
||||
"add_if_max [element] : добавить новый элемент в коллекцию, если его значение превышает значение наибольшего элемента этой коллекции\n" +
|
||||
"add_if_min [element] : добавить новый элемент в коллекцию, если его значение меньше, чем у наименьшего элемента этой коллекции\n" +
|
||||
"history : вывести последние 6 команд (без их аргументов)\n" +
|
||||
"sum_of_height : вывести сумму значений поля height для всех элементов коллекции\n" +
|
||||
"filter_contains_name {name} : вывести элементы, значение поля name которых содержит заданную подстроку\n" +
|
||||
"print_field_descending_location : вывести значения поля location всех элементов в порядке убывания\n" +
|
||||
LINE + "\n";
|
||||
/**
|
||||
* Коллекция, на основе которой функционирует данный класс
|
||||
*/
|
||||
private final PersonTreeSet personTreeSet;
|
||||
/**
|
||||
* Логическая переменная, хранящая состояние программы
|
||||
*/
|
||||
private boolean isActive = false;
|
||||
/**
|
||||
* Очередь входных потоков, используется для выполнения пользовательских скриптов,
|
||||
* также требуется для реализации возможности рекурсивного выполнения скриптов
|
||||
*/
|
||||
private final Queue<InputStream> inputStreams = new LinkedList<>();
|
||||
/**
|
||||
* Reader, использующийся для чтения пользовательских команд или скриптов
|
||||
*/
|
||||
private BufferedReader reader;
|
||||
/**
|
||||
* Список последних 6 выполненных команд
|
||||
*/
|
||||
private final LinkedList<String> history = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Конструктор класса
|
||||
*
|
||||
* @param personTreeSet Коллекция типа {@link PersonTreeSet PersonTreeSet}
|
||||
*/
|
||||
public CommandParser(PersonTreeSet personTreeSet) {
|
||||
this.personTreeSet = personTreeSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, открывающий поток ввода данных и запускающий программу,
|
||||
* циклически вызывая функцию {@link #parse() parse}
|
||||
*/
|
||||
public void start() {
|
||||
System.out.println(GREETINGS);
|
||||
reader = new BufferedReader(new InputStreamReader(System.in));
|
||||
this.isActive = true;
|
||||
do {
|
||||
parse();
|
||||
} while (this.isActive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Основной метод, который ждет от пользователя ввода данных, после чего
|
||||
* делит строку на команду и её аргументы, и в зависимости от них,
|
||||
* вызывает нужную функцию на выполнение
|
||||
*/
|
||||
public void parse() {
|
||||
String input = awaitInput("", "Что-то пошло не так").toLowerCase(Locale.ROOT);
|
||||
String[] split = input.split(" ");
|
||||
String command = split[0], argument = split.length > 1 ? split[1] : null;
|
||||
switch (command) {
|
||||
case "help": help(); break;
|
||||
case "info": info(); break;
|
||||
case "show": show(); break;
|
||||
case "add": add(); break;
|
||||
case "update": update(argument); break;
|
||||
case "remove_by_id": removeByID(argument); break;
|
||||
case "clear": clear(); break;
|
||||
case "save": save(); break;
|
||||
case "execute_script": executeScript(argument); break;
|
||||
case "exit": exit(); break;
|
||||
case "add_if_max": addIfMax(); break;
|
||||
case "add_if_min": addIfMin(); break;
|
||||
case "history": history(); break;
|
||||
case "sum_of_height": sumOfHeight(); break;
|
||||
case "filter_contains_name": filterContainsName(argument); break;
|
||||
case "print_field_descending_location": printFieldDescendingLocation(); break;
|
||||
default: unknown(); return;
|
||||
}
|
||||
updateHistory(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, обновляющий историю введенных команд
|
||||
*
|
||||
* @param command Введенная команда
|
||||
*/
|
||||
private void updateHistory(String command) {
|
||||
history.add(command);
|
||||
if (this.history.size() > 6)
|
||||
this.history.removeFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе неизвестной команды
|
||||
*/
|
||||
public void unknown() {
|
||||
System.err.println("Неизвестная команда. Введите help для отображения списка всех команд");
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды help,
|
||||
* печатает содержимое строки {@link #HELP HELP}
|
||||
*/
|
||||
public void help() {
|
||||
System.out.println(CommandParser.HELP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды info,
|
||||
* печатает информацию о коллекции
|
||||
*/
|
||||
public void info() {
|
||||
System.out.println(this.personTreeSet.info());
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды show,
|
||||
* печатает содержимое коллекции
|
||||
*/
|
||||
public void show() {
|
||||
System.out.println("Вся коллекция PersonTreeSet:");
|
||||
System.out.println(this.personTreeSet.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды add,
|
||||
* пытается добавить новый элемент в коллекцию,
|
||||
* печатает результат добавления
|
||||
*/
|
||||
public void add() {
|
||||
Person person = createPerson();
|
||||
boolean success = this.personTreeSet.add(person);
|
||||
String msg = success ? "Объект был добавлен в коллекцию" : "Не удалось добавить объект";
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды update,
|
||||
* пытается изменить существующий элемент коллекции по заданному id
|
||||
* печатает результат изменения
|
||||
*
|
||||
* @param id Id человека
|
||||
*/
|
||||
public void update(long id) {
|
||||
if (Person.getExistingPeople() < id || id <= 0) {
|
||||
System.err.println("Не удалось найти объект с id " + id);
|
||||
return;
|
||||
}
|
||||
Person person = createPerson();
|
||||
boolean success = this.personTreeSet.update(id, person);
|
||||
String msg = success ? "Объект был успешно изменен" : "Не удалось найти объект с id " + id;
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, аналогичный {@link #update(long) update(long)},
|
||||
* пытается преобразовать данную строку в Long и вызвать {@link #update(long) update(long)}
|
||||
*
|
||||
* @param strId Id человека типа String
|
||||
*/
|
||||
public void update(String strId) {
|
||||
Long id = idOrNull(strId);
|
||||
if (id != null)
|
||||
update(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды remove_by_id,
|
||||
* пытается удалить существующий элемент из коллекции по заданному id
|
||||
* печатает результат изменения
|
||||
*
|
||||
* @param id Id человека
|
||||
*/
|
||||
public void removeByID(long id) {
|
||||
boolean success = this.personTreeSet.remove(id);
|
||||
String msg = success ? "Объект был удален" : "Не удалось найти объект с id " + id;
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, аналогичный {@link #removeByID(long) update(long)},
|
||||
* пытается преобразовать данную строку в Long и вызвать {@link #update(long) update(long)}
|
||||
*
|
||||
* @param strId Id человека типа String
|
||||
*/
|
||||
public void removeByID(String strId) {
|
||||
Long id = idOrNull(strId);
|
||||
if (id != null)
|
||||
removeByID(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, преобразующий строковый id в Long,
|
||||
* печатает результат преобразования
|
||||
*
|
||||
* @param strId Преобразуемая строка
|
||||
* @return Преобразованная строка в Long или null при ошибке
|
||||
*/
|
||||
public Long idOrNull(String strId) {
|
||||
long id;
|
||||
if (strId == null) {
|
||||
System.err.println("Параметр id должен быть указан");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
id = Long.parseLong(strId);
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Параметр id должен являться целым числом");
|
||||
return null;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды clear, очищает коллекцию
|
||||
*/
|
||||
public void clear() {
|
||||
this.personTreeSet.clear();
|
||||
System.out.println("Коллекция успешно очищена");
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды save,
|
||||
* пытается сохранить коллекцию в файл,
|
||||
* печатает результат сохранения
|
||||
*/
|
||||
public void save() {
|
||||
boolean success = this.personTreeSet.save();
|
||||
String msg = success ? "Коллекция была сохранена в файле " + this.personTreeSet.getFile().getAbsolutePath()
|
||||
: "Не удалось сохранить коллекцию (обычно причина пишется при запуске программы)";
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды execute_script,
|
||||
* пытается выполнить скрипт, написанный в файле fileName,
|
||||
* печатает результат выполнения скрипта
|
||||
*
|
||||
* @param fileName Имя или путь к файлу
|
||||
*/
|
||||
public void executeScript(String fileName) {
|
||||
if (fileName == null || fileName.isEmpty()) {
|
||||
System.err.println("Параметр file_name должен быть указан");
|
||||
return;
|
||||
}
|
||||
File file = new File(fileName);
|
||||
if (!file.exists() || file.isDirectory()) {
|
||||
System.err.println("Не удалось найти указанный файл со скриптом");
|
||||
return;
|
||||
}
|
||||
InputStream stream;
|
||||
try {
|
||||
stream = new FileInputStream(file);
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println("Файл не найден");
|
||||
return;
|
||||
}
|
||||
newInputStream(stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды exit,
|
||||
* заканчивает выполнение программы, предлагая перед этим сохранить коллекцию
|
||||
*/
|
||||
public void exit() {
|
||||
if (this.personTreeSet.getFile() != null) {
|
||||
String answer = awaitInput("Сохранить коллекцию в файл? (Y - да, N - нет)", "Введите Y или N",
|
||||
input -> input.toUpperCase(Locale.ROOT).equals("Y") || input.toUpperCase(Locale.ROOT).equals("N"),
|
||||
input -> input.toUpperCase(Locale.ROOT));
|
||||
if (answer.equals("Y"))
|
||||
save();
|
||||
}
|
||||
System.out.println("Выход из программы...");
|
||||
this.isActive = false;
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды add_if_max,
|
||||
* пытается добавить новый элемент в коллекцию, только если он больше максимального элемента в коллекции
|
||||
* печатает результат добавления
|
||||
*/
|
||||
public void addIfMax() {
|
||||
Person person = createPerson();
|
||||
boolean success = this.personTreeSet.addIfMax(person);
|
||||
String msg = success ? "Объект был добавлен в коллекцию" : "Не удалось добавить объект";
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды add_if_min,
|
||||
* пытается добавить новый элемент в коллекцию, только если он меньше минимального элемента в коллекции
|
||||
* печатает результат добавления
|
||||
*/
|
||||
public void addIfMin() {
|
||||
Person person = createPerson();
|
||||
boolean success = this.personTreeSet.addIfMin(person);
|
||||
String msg = success ? "Объект был добавлен в коллекцию" : "Не удалось добавить объект";
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды history,
|
||||
* печатает историю последних 6 введенных команд
|
||||
*/
|
||||
public void history() {
|
||||
System.out.println("История последних 6 команд:");
|
||||
this.history.forEach(System.out::println);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вызываемый при вводе команды sum_of_height,
|
||||
* печатает суммарный рост всех людей в коллекции
|
||||
*/
|
||||
public void sumOfHeight() {
|
||||
int sum = this.personTreeSet.sumOfHeight();
|
||||
System.out.println("Сумма ростов всех людей в коллекции: " + sum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, фильтрующий и печатающий всех людей, в имени которых имеется строка name,
|
||||
* проверка не чувствительна к регистру
|
||||
*
|
||||
* @param name Строка, по которой происходит фильтрация
|
||||
*/
|
||||
public void filterContainsName(String name) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
System.err.println("Параметр name должен быть указан");
|
||||
return;
|
||||
}
|
||||
List<Person> people = this.personTreeSet.filterContainsName(name);
|
||||
System.out.println("Список людей, в имени которых содержится " + name + ":");
|
||||
people.forEach(System.out::println);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, печатающий отсортированный по убыванию список местоположений всех людей в коллекции
|
||||
*/
|
||||
public void printFieldDescendingLocation() {
|
||||
List<Location> locations = this.personTreeSet.fieldDescendingLocation();
|
||||
System.out.println("Список локаций в порядке убывания:");
|
||||
locations.forEach(System.out::println);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, интерактивно создающий нового человека, получая каждое новое значение из потока ввода {@link #reader reader}
|
||||
*
|
||||
* @return Новый экземпляр класса {@link Person Person}
|
||||
*/
|
||||
private Person createPerson() {
|
||||
System.out.println("Создание нового объекта класса Person");
|
||||
Person person = new Person();
|
||||
person.setName(
|
||||
awaitInput("Введите имя:", "Введите непустую строку",
|
||||
input -> !input.isEmpty())
|
||||
);
|
||||
person.setHeight(
|
||||
awaitInput("Введите рост:", "Введите целое число, большее нуля",
|
||||
input -> {
|
||||
try {
|
||||
int num = Integer.parseInt(input);
|
||||
return num > 0;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}, Integer::parseInt)
|
||||
);
|
||||
person.setPassportID(
|
||||
awaitInput("Введите номер паспорта:", "Введите как минимум 8 символов",
|
||||
input -> input.length() >= 8)
|
||||
);
|
||||
person.setEyeColor(
|
||||
awaitInput("Введите цвет глаз (BLACK, ORANGE, BROWN):", "Введите один из предложенных цветов",
|
||||
input -> Color.isColorValid(input.toUpperCase(Locale.ROOT)), input -> Color.valueOf(input.toUpperCase(Locale.ROOT)))
|
||||
);
|
||||
person.setNationality(
|
||||
awaitInput("Введите страну (UNITED_KINGDOM, GERMANY, CHINA, THAILAND, JAPAN):", "Введите одну из предлженных стран",
|
||||
input -> Country.isCountryValid(input.toUpperCase(Locale.ROOT)), input -> Country.valueOf(input.toUpperCase(Locale.ROOT)))
|
||||
);
|
||||
person.setCoordinates(createCoordinates());
|
||||
person.setLocation(createLocation());
|
||||
return person;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, интерактивно создающий новые координаты, получая каждое новое значение из потока ввода {@link #reader reader}
|
||||
*
|
||||
* @return Новый экземпляр класса {@link Coordinates Coordinates}
|
||||
*/
|
||||
private Coordinates createCoordinates() {
|
||||
System.out.println("Создание нового объекта класса Coordinates");
|
||||
Coordinates coordinates = new Coordinates();
|
||||
coordinates.setX(
|
||||
awaitInput("Введите x:", "Введите дробное число",
|
||||
input -> {
|
||||
try {
|
||||
Float.parseFloat(input);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}, Float::parseFloat)
|
||||
);
|
||||
coordinates.setY(
|
||||
awaitInput("Введите y:", "Введите дробное число, большее -816",
|
||||
input -> {
|
||||
try {
|
||||
float num = Float.parseFloat(input);
|
||||
return num > -816F;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}, Float::parseFloat)
|
||||
);
|
||||
return coordinates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, интерактивно создающий новое местоположение, получая каждое новое значение из потока ввода {@link #reader reader}
|
||||
*
|
||||
* @return Новый экземпляр класса {@link Location Location}
|
||||
*/
|
||||
private Location createLocation() {
|
||||
System.out.println("Создание нового объекта класса Location");
|
||||
Location location = new Location();
|
||||
location.setX(
|
||||
awaitInput("Введите x:", "Введите дробное число",
|
||||
input -> {
|
||||
try {
|
||||
Double.parseDouble(input);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}, Double::parseDouble)
|
||||
);
|
||||
location.setY(
|
||||
awaitInput("Введите y:", "Введите дробное число",
|
||||
input -> {
|
||||
try {
|
||||
Double.parseDouble(input);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}, Float::parseFloat)
|
||||
);
|
||||
location.setZ(
|
||||
awaitInput("Введите z:", "Введите целое число",
|
||||
input -> {
|
||||
try {
|
||||
Long.parseLong(input);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}, Long::parseLong)
|
||||
);
|
||||
location.setName(
|
||||
awaitInput("Введите название:", "Введите непустую строку",
|
||||
input -> !input.isEmpty())
|
||||
);
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, ожидающий ввода из потока ввода {@link #reader reader} и возвращающий результат,,
|
||||
* печатает запрос msg перед ожиданием данных (если их вводит пользователь),
|
||||
* печатает ошибку err, если при вводе данных произошла ошибка
|
||||
*
|
||||
* @param msg Строка, печатающаяся как запрос данных от пользователя
|
||||
* @param err Строка, печатающаяся во время ошибки
|
||||
*
|
||||
* @return Строка из потока ввода
|
||||
*/
|
||||
private String awaitInput(String msg, String err) {
|
||||
return awaitInput(msg, err, input -> true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, ожидающий ввода из потока ввода {@link #reader reader } и возвращающий результат,,
|
||||
* печатает запрос msg перед ожиданием данных (если их вводит пользователь),
|
||||
* печатает ошибку err, если введенные данные не соответствуют предикату predicate
|
||||
*
|
||||
* @param msg Строка, печатающаяся как запрос данных от пользователя
|
||||
* @param err Строка, печатающаяся при несоответствии ввода предикату
|
||||
* @param predicate Предикат, определяющий валидность введенных данных
|
||||
*
|
||||
* @return Строка из потока ввода
|
||||
*/
|
||||
private String awaitInput(String msg, String err, Predicate<String> predicate) {
|
||||
String input = null;
|
||||
do {
|
||||
if (inputStreams.isEmpty())
|
||||
System.out.print(msg + "\n>>> ");
|
||||
try {
|
||||
input = reader.readLine();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (input == null) {
|
||||
prevInputStream();
|
||||
continue;
|
||||
}
|
||||
if (predicate.test(input.trim()))
|
||||
break;
|
||||
else
|
||||
System.err.println(err);
|
||||
} while (true);
|
||||
System.out.println();
|
||||
return input.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, ожидающий ввода из потока ввода {@link #reader reader} и возвращающий результат,
|
||||
* печатает запрос msg перед ожиданием данных (если их вводит пользователь),
|
||||
* печатает ошибку err, если введенные данные не соответствуют предикату predicate,
|
||||
* преобразует результат в тип T в соответствии с функцией transform
|
||||
*
|
||||
* @param msg Строка, печатающаяся как запрос данных от пользователя
|
||||
* @param err Строка, печатающаяся при несоответствии ввода предикату
|
||||
* @param predicate Предикат, определяющий валидность введенных данных
|
||||
* @param <T> Тип, к которому будет приведен результат
|
||||
* @param transform Функция, преобразующая результат в тип T
|
||||
*
|
||||
* @return Результат типа T
|
||||
*/
|
||||
private <T> T awaitInput(String msg, String err, Predicate<String> predicate, Function<String, T> transform) {
|
||||
String result = awaitInput(msg, err, predicate);
|
||||
return transform.apply(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, меняющий текущий поток ввода на stream и добавляет его в очередь {@link #inputStreams inputStreams}
|
||||
*
|
||||
* @param stream Новый поток ввода
|
||||
*/
|
||||
private void newInputStream(InputStream stream) {
|
||||
this.reader = new BufferedReader(new InputStreamReader(stream));
|
||||
this.inputStreams.add(stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, убирающий текущий поток ввода из очереди {@link #inputStreams inputStreams}
|
||||
* и меняющий его либо на следующий в очереди поток, либо на System.in, если очередь пуста
|
||||
*/
|
||||
private void prevInputStream() {
|
||||
inputStreams.poll();
|
||||
InputStream stream = inputStreams.isEmpty() ? System.in : inputStreams.peek();
|
||||
this.reader = new BufferedReader(new InputStreamReader(stream));
|
||||
}
|
||||
}
|
26
src/main/java/ru/erius/lab5/collection/Color.java
Normal file
26
src/main/java/ru/erius/lab5/collection/Color.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package ru.erius.lab5.collection;
|
||||
|
||||
/**
|
||||
* Перечисление цветов
|
||||
*/
|
||||
public enum Color {
|
||||
BLACK,
|
||||
ORANGE,
|
||||
BROWN;
|
||||
|
||||
/**
|
||||
* Метод, проверяющий, можно ли из данной строки получить значение типа Color
|
||||
*
|
||||
* @param strColor Проверяемая строка
|
||||
*
|
||||
* @return true, если из строки можно получить значение типа Color, иначе false
|
||||
*/
|
||||
public static boolean isColorValid(String strColor) {
|
||||
try {
|
||||
Color.valueOf(strColor);
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
88
src/main/java/ru/erius/lab5/collection/Coordinates.java
Normal file
88
src/main/java/ru/erius/lab5/collection/Coordinates.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
package ru.erius.lab5.collection;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Класс данных координат
|
||||
*/
|
||||
public class Coordinates {
|
||||
|
||||
/**
|
||||
* Координата X типа float
|
||||
*/
|
||||
private float x;
|
||||
/**
|
||||
* Координата Y типа float, значение должно быть больше -816
|
||||
*/
|
||||
private float y;
|
||||
|
||||
/**
|
||||
* Конструктор без параметров, задаёт значения всех полей по умолчанию,
|
||||
* x = 0, y = 0
|
||||
*/
|
||||
public Coordinates() {
|
||||
this.x = 0F;
|
||||
this.y = 0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Конструктор с параметрами
|
||||
*
|
||||
* @param x Координата X
|
||||
* @param y Координата Y
|
||||
*
|
||||
* @throws IllegalArgumentException Если Y меньше или равен -816
|
||||
*/
|
||||
public Coordinates(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setX(float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Сеттер для поля y
|
||||
*
|
||||
* @param y Координата Y
|
||||
*
|
||||
* @throws IllegalArgumentException Если Y меньше или равен -816
|
||||
*/
|
||||
public void setY(float y) {
|
||||
this.y = y;
|
||||
if (y <= -816)
|
||||
throw new IllegalArgumentException("Поле y класса Coordinates должно быть больше -816");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) return true;
|
||||
if (other == null || getClass() != other.getClass()) return false;
|
||||
|
||||
Coordinates that = (Coordinates) other;
|
||||
|
||||
if (Float.compare(that.x, x) != 0) return false;
|
||||
return Float.compare(that.y, y) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (x != 0.0f ? Float.floatToIntBits(x) : 0);
|
||||
result = 31 * result + (y != 0.0f ? Float.floatToIntBits(y) : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(Locale.US, "Coordinates(x=%f, y=%f)", this.x, this.y);
|
||||
}
|
||||
}
|
28
src/main/java/ru/erius/lab5/collection/Country.java
Normal file
28
src/main/java/ru/erius/lab5/collection/Country.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
package ru.erius.lab5.collection;
|
||||
|
||||
/**
|
||||
* Перечисление стран
|
||||
*/
|
||||
public enum Country {
|
||||
UNITED_KINGDOM,
|
||||
GERMANY,
|
||||
CHINA,
|
||||
THAILAND,
|
||||
JAPAN;
|
||||
|
||||
/**
|
||||
* Метод, проверяющий, можно ли из данной строки получить значение типа Country
|
||||
*
|
||||
* @param strCountry Проверяемая строка
|
||||
*
|
||||
* @return true, если из строки можно получить значение типа Country, иначе false
|
||||
*/
|
||||
public static boolean isCountryValid(String strCountry) {
|
||||
try {
|
||||
Country.valueOf(strCountry);
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
160
src/main/java/ru/erius/lab5/collection/Location.java
Normal file
160
src/main/java/ru/erius/lab5/collection/Location.java
Normal file
|
@ -0,0 +1,160 @@
|
|||
package ru.erius.lab5.collection;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Класс данных местоположения, реализует сортировку по умолчанию
|
||||
* по имени и расстоянию до точки (0; 0; 0)
|
||||
*/
|
||||
public class Location implements Comparable<Location> {
|
||||
|
||||
/**
|
||||
* Координата X типа double
|
||||
*/
|
||||
private double x;
|
||||
/**
|
||||
* Координата Y типа float
|
||||
*/
|
||||
private float y;
|
||||
/**
|
||||
* Координата Z типа Long, не может быть null
|
||||
*/
|
||||
private Long z;
|
||||
/**
|
||||
* Имя локации, может быть null
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Конструктор без параметров, задаёт значения всех полей по умолчанию,
|
||||
* x = 0, y = 0, z = 0, name = null
|
||||
*/
|
||||
public Location() {
|
||||
this.x = 0D;
|
||||
this.y = 0F;
|
||||
this.z = 0L;
|
||||
this.name = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Конструктор с параметрами
|
||||
*
|
||||
* @param x Координата X
|
||||
* @param y Координата Y
|
||||
* @param z Координата Z
|
||||
* @param name Имя локации
|
||||
*
|
||||
* @throws IllegalArgumentException Данное исключение будет брошено в следующих случаях:
|
||||
* Z является null,
|
||||
* name является пустой строкой
|
||||
*/
|
||||
public Location(double x, float y, Long z, String name) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.setZ(z);
|
||||
this.setName(name);
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Long getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setX(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public void setY(float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Сеттер для поля z
|
||||
* @param z Координата Z
|
||||
*
|
||||
* @throws IllegalArgumentException Если Z является null
|
||||
*/
|
||||
public void setZ(Long z) {
|
||||
this.z = z;
|
||||
if (z == null)
|
||||
throw new IllegalArgumentException("Поле z класса Location не может быть null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Сеттер для поля name
|
||||
* @param name Имя локации
|
||||
*
|
||||
* @throws IllegalArgumentException Если name является пустой строкой
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
if (name.isEmpty())
|
||||
throw new IllegalArgumentException("Поле name класса Location не может быть пустым");
|
||||
}
|
||||
|
||||
/**
|
||||
* Переопределенный метод сравнения двух местоположений,
|
||||
* сравнение производится по имени локации и расстоянию до точки (0; 0; 0)
|
||||
*
|
||||
* @param other Объект для сравнения
|
||||
* @return Целое число - результат сравнения
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Location other) {
|
||||
return Comparator.comparing(Location::getName)
|
||||
.thenComparing(Location::distance)
|
||||
.compare(this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, вычисляющий расстояние до точки (0; 0; 0)
|
||||
*
|
||||
* @return Расстояние типа double
|
||||
*/
|
||||
private double distance() {
|
||||
return Math.sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) return true;
|
||||
if (other == null || getClass() != other.getClass()) return false;
|
||||
|
||||
Location location = (Location) other;
|
||||
|
||||
if (Double.compare(location.x, x) != 0) return false;
|
||||
if (Float.compare(location.y, y) != 0) return false;
|
||||
if (!z.equals(location.z)) return false;
|
||||
return Objects.equals(name, location.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(x);
|
||||
result = (int) (temp ^ (temp >>> 32));
|
||||
result = 31 * result + (y != 0.0f ? Float.floatToIntBits(y) : 0);
|
||||
result = 31 * result + z.hashCode();
|
||||
result = 31 * result + (name != null ? name.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(Locale.US, "Location(x=%f, y=%f, z=%s, name=%s)", this.x, this.y, this.z, this.name);
|
||||
}
|
||||
}
|
337
src/main/java/ru/erius/lab5/collection/Person.java
Normal file
337
src/main/java/ru/erius/lab5/collection/Person.java
Normal file
|
@ -0,0 +1,337 @@
|
|||
package ru.erius.lab5.collection;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Класс данных человека, реализует сортировку по умолчанию по имени, номеру паспорта,
|
||||
* росту, национальности, местоположению и цвету глаз
|
||||
*/
|
||||
public class Person implements Comparable<Person> {
|
||||
|
||||
/**
|
||||
* Количество созданных людей, используется для задания
|
||||
* уникального id для каждого объекта данного класса
|
||||
*/
|
||||
private static long existingPeople = 0;
|
||||
|
||||
/**
|
||||
* Регулярное выражение для валидации и создания
|
||||
* экземпляров данного класса из строк
|
||||
*/
|
||||
private final static Pattern PERSON_REGEX = Pattern.compile(
|
||||
"Person\\(\\s*id=(?<id>\\d+),\\s*name=(?<name>\\S+)," +
|
||||
"\\s*coordinates=Coordinates\\(x=(?<coordX>[+-]?(\\d+([.,]\\d*)?|[.,]\\d+)),\\s*y=(?<coordY>[+-]?(\\d+([.,]\\d*)?|[.,]\\d+))\\)," +
|
||||
"\\s*creationDate=(?<creationDate>\\d{4}[\\-.]\\d{2}[\\-.]\\d{2}),\\s*height=(?<height>\\d+),\\s*passportID=(?<passportID>\\S{8,})," +
|
||||
"\\s*eyeColor=(?<eyeColor>\\w+),\\s*nationality=(?<nationality>\\w+),\\" +
|
||||
"s*location=Location\\(x=(?<locX>[+-]?(\\d+([.,]\\d*)?|[.,]\\d+)),\\s*y=(?<locY>[+-]?(\\d+([.,]\\d*)?|[.,]\\d+))," +
|
||||
"\\s*z=(?<locZ>[+-]?\\d+),\\s*name=(?<locName>\\S+)\\)\\)"
|
||||
);
|
||||
|
||||
/**
|
||||
* Id человека, не может быть null, значение поля должно быть больше 0,
|
||||
* значение этого поля должно быть уникальным, значение этого поля должно генерироваться автоматически
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* Имя человека, не может быть null, строка не может быть пустой
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* Координаты человека, не может быть null
|
||||
*/
|
||||
private Coordinates coordinates;
|
||||
/**
|
||||
* Дата создания объекта, не может быть null, значение этого поля должно генерироваться автоматически
|
||||
*/
|
||||
private LocalDate creationDate;
|
||||
/**
|
||||
* Рост человека, может быть null, значение поля должно быть больше 0
|
||||
*/
|
||||
private Integer height;
|
||||
/**
|
||||
* Номер паспорта человека, длина строки должна быть не меньше 8, поле может быть null
|
||||
*/
|
||||
private String passportID;
|
||||
/**
|
||||
* Цвет глаз человека, не может быть null
|
||||
*/
|
||||
private Color eyeColor;
|
||||
/**
|
||||
* Национальность человека, не может быть null
|
||||
*/
|
||||
private Country nationality;
|
||||
/**
|
||||
* Местоположение человека, может быть null
|
||||
*/
|
||||
private Location location;
|
||||
|
||||
/**
|
||||
* Конструктор без параметров, задаёт значения всех полей по умолчанию,
|
||||
* name = "None", coordinates = new Coordinates(), height = 1,
|
||||
* passportID = null, eyeColor = Color.BLACK, nationality = Country.UNITED_KINGDOM
|
||||
*/
|
||||
public Person() {
|
||||
this.id = ++existingPeople;
|
||||
this.creationDate = LocalDate.now();
|
||||
this.location = null;
|
||||
this.name = "None";
|
||||
this.coordinates = new Coordinates();
|
||||
this.height = 1;
|
||||
this.passportID = null;
|
||||
this.eyeColor = Color.BLACK;
|
||||
this.nationality = Country.UNITED_KINGDOM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Конструктор с параметрами
|
||||
*
|
||||
* @param name Имя человека
|
||||
* @param coordinates Координаты человека
|
||||
* @param height Высота человека
|
||||
* @param passportID Номер паспорта человека
|
||||
* @param eyeColor Цвет глаз человека
|
||||
* @param nationality Национальность человека
|
||||
* @param location Местоположение человека
|
||||
*
|
||||
* @throws IllegalArgumentException Данное исключение будет брошено в следующих случаях:
|
||||
* name является null или пустой строкой,
|
||||
* coordinates является null,
|
||||
* height меньше 0,
|
||||
* Длина passportID меньше 8 символов,
|
||||
* eyeColor является null,
|
||||
* nationality является null
|
||||
*/
|
||||
public Person(String name, Coordinates coordinates, Integer height, String passportID,
|
||||
Color eyeColor, Country nationality, Location location) {
|
||||
this.id = ++existingPeople;
|
||||
this.creationDate = LocalDate.now();
|
||||
this.location = location;
|
||||
this.setName(name);
|
||||
this.setCoordinates(coordinates);
|
||||
this.setHeight(height);
|
||||
this.setPassportID(passportID);
|
||||
this.setEyeColor(eyeColor);
|
||||
this.setNationality(nationality);
|
||||
}
|
||||
|
||||
public static long getExistingPeople() {
|
||||
return existingPeople;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Coordinates getCoordinates() {
|
||||
return coordinates;
|
||||
}
|
||||
|
||||
public Integer getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public String getPassportID() {
|
||||
return passportID;
|
||||
}
|
||||
|
||||
public Color getEyeColor() {
|
||||
return eyeColor;
|
||||
}
|
||||
|
||||
public Country getNationality() {
|
||||
return nationality;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Сеттер для поля name
|
||||
*
|
||||
* @param name Имя человека
|
||||
*
|
||||
* @throws IllegalArgumentException Если имя является null или пустой строкой
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
if (name == null || name.isEmpty())
|
||||
throw new IllegalArgumentException("Поле name класса Person не может быть null или пустым");
|
||||
}
|
||||
|
||||
/**
|
||||
* Сеттер для поля coordinates
|
||||
*
|
||||
* @param coordinates Координаты человека
|
||||
*
|
||||
* @throws IllegalArgumentException Если объект координат является null
|
||||
*/
|
||||
public void setCoordinates(Coordinates coordinates) {
|
||||
this.coordinates = coordinates;
|
||||
if (coordinates == null)
|
||||
throw new IllegalArgumentException("Поле coordinates класса Person не может быть null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Сеттер для поля height
|
||||
*
|
||||
* @param height Рост человека
|
||||
*
|
||||
* @throws IllegalArgumentException Если рост меньше 0
|
||||
*/
|
||||
public void setHeight(Integer height) {
|
||||
this.height = height;
|
||||
if (height <= 0)
|
||||
throw new IllegalArgumentException("Поле height класса Person должно быть больше 0");
|
||||
}
|
||||
|
||||
/**
|
||||
* Сеттер для поля passportID
|
||||
*
|
||||
* @param passportID Номер паспорта человека
|
||||
*
|
||||
* @throws IllegalArgumentException Если номер паспорта меньше 8 символов в длину
|
||||
*/
|
||||
public void setPassportID(String passportID) {
|
||||
this.passportID = passportID;
|
||||
if (passportID.length() < 8)
|
||||
throw new IllegalArgumentException("Поле passportID класса Person не может быть меньше 8 символов в длину");
|
||||
}
|
||||
|
||||
/**
|
||||
* Сеттер для поля eyeColor
|
||||
*
|
||||
* @param eyeColor Координаты человека
|
||||
*
|
||||
* @throws IllegalArgumentException Если цвет глаз является null
|
||||
*/
|
||||
public void setEyeColor(Color eyeColor) {
|
||||
this.eyeColor = eyeColor;
|
||||
if (eyeColor == null)
|
||||
throw new IllegalArgumentException("Поле eyeColor класса Person не может быть null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Сеттер для поля nationality
|
||||
*
|
||||
* @param nationality Координаты человека
|
||||
*
|
||||
* @throws IllegalArgumentException Если национальность является null
|
||||
*/
|
||||
public void setNationality(Country nationality) {
|
||||
this.nationality = nationality;
|
||||
if (nationality == null)
|
||||
throw new IllegalArgumentException("Поле nationality класса Person не может быть null");
|
||||
}
|
||||
|
||||
public void setLocation(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Статический метод, возвращающий список объектов Person,
|
||||
* образованный из найденных в строке совпадений с
|
||||
* регулярным выражением {@link #PERSON_REGEX PERSON_REGEX}
|
||||
*
|
||||
* @param str Строка, из которой требуется получить список людей
|
||||
* @return Список объектов класса Person
|
||||
*/
|
||||
public static List<Person> peopleFromString(String str) {
|
||||
List<Person> list = new ArrayList<>();
|
||||
Matcher matcher = PERSON_REGEX.matcher(str);
|
||||
while (matcher.find()) {
|
||||
try {
|
||||
Person person = new Person();
|
||||
person.id = Long.parseLong(matcher.group("id"));
|
||||
person.name = matcher.group("name");
|
||||
person.height = Integer.parseInt(matcher.group("height"));
|
||||
person.passportID = matcher.group("passportID");
|
||||
person.eyeColor = Color.valueOf(matcher.group("eyeColor"));
|
||||
person.nationality = Country.valueOf(matcher.group("nationality"));
|
||||
person.coordinates = new Coordinates(
|
||||
Float.parseFloat(matcher.group("coordX")),
|
||||
Float.parseFloat(matcher.group("coordY"))
|
||||
);
|
||||
person.location = new Location(
|
||||
Double.parseDouble(matcher.group("locX")),
|
||||
Float.parseFloat(matcher.group("locY")),
|
||||
Long.parseLong(matcher.group("locZ")),
|
||||
matcher.group("locName")
|
||||
);
|
||||
String[] date = matcher.group("creationDate").split("[\\-.]");
|
||||
person.creationDate = LocalDate.of(
|
||||
Integer.parseInt(date[0]),
|
||||
Integer.parseInt(date[1]),
|
||||
Integer.parseInt(date[2])
|
||||
);
|
||||
list.add(person);
|
||||
} catch (NumberFormatException | DateTimeException e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Что-то пошло не так при чтении данных из файла, не меняйте вручную данные в файле!!!");
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Переопределенный метод сравнения двух людей,
|
||||
* сравнение производится по имени, номеру пасспорта,
|
||||
* росту, национальности, местоположению и цвету глаз
|
||||
*
|
||||
* @param other Объект для сравнения
|
||||
* @return Целое число - результат сравнения
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Person other) {
|
||||
return Comparator.comparing(Person::getName)
|
||||
.thenComparing(Person::getPassportID)
|
||||
.thenComparing(Person::getHeight)
|
||||
.thenComparing(Person::getNationality)
|
||||
.thenComparing(Person::getLocation)
|
||||
.thenComparing(Person::getEyeColor)
|
||||
.compare(this, other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) return true;
|
||||
if (other == null || getClass() != other.getClass()) return false;
|
||||
|
||||
Person person = (Person) other;
|
||||
|
||||
if (!name.equals(person.name)) return false;
|
||||
if (!coordinates.equals(person.coordinates)) return false;
|
||||
if (!Objects.equals(height, person.height)) return false;
|
||||
if (!Objects.equals(passportID, person.passportID)) return false;
|
||||
if (eyeColor != person.eyeColor) return false;
|
||||
if (nationality != person.nationality) return false;
|
||||
return Objects.equals(location, person.location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.hashCode();
|
||||
result = 31 * result + coordinates.hashCode();
|
||||
result = 31 * result + (height != null ? height.hashCode() : 0);
|
||||
result = 31 * result + (passportID != null ? passportID.hashCode() : 0);
|
||||
result = 31 * result + eyeColor.hashCode();
|
||||
result = 31 * result + nationality.hashCode();
|
||||
result = 31 * result + (location != null ? location.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(Locale.US, "Person(id=%d, name=%s, coordinates=%s, creationDate=%s, height=%s, passportID=%s, " +
|
||||
"eyeColor=%s, nationality=%s, location=%s)", this.id, this.name, this.coordinates, this.creationDate,
|
||||
this.height, this.passportID, this.eyeColor, this.nationality, this.location);
|
||||
}
|
||||
}
|
295
src/main/java/ru/erius/lab5/collection/PersonTreeSet.java
Normal file
295
src/main/java/ru/erius/lab5/collection/PersonTreeSet.java
Normal file
|
@ -0,0 +1,295 @@
|
|||
package ru.erius.lab5.collection;
|
||||
|
||||
import java.io.*;
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Коллекция PersonTreeSet, использующая в основе своей работы коллекцию {@link TreeSet TreeSet},
|
||||
* имеет возможности записи коллекции в файл и чтения её же из файла
|
||||
*/
|
||||
public class PersonTreeSet {
|
||||
/**
|
||||
* Название переменной окружения, где должен быть указан путь к файлу
|
||||
*/
|
||||
private final static String ENV_VAR = "PTS_PATH";
|
||||
/**
|
||||
* Тип коллекции, используется для вывода информации
|
||||
*/
|
||||
private final static String TYPE = "TreeSet";
|
||||
|
||||
/**
|
||||
* Файл для записи и чтения коллекции, является null если путь к файлу некорректный
|
||||
*/
|
||||
private final File file = initFile();
|
||||
/**
|
||||
* Логические переменные, определяющие возможность программы записывать в файл или читать из него
|
||||
*/
|
||||
private boolean canWrite = true, canRead = true;
|
||||
/**
|
||||
* Коллекция {@link TreeSet TreeSet}, лежащая в основе работы класса
|
||||
*/
|
||||
private final TreeSet<Person> set = new TreeSet<>();
|
||||
/**
|
||||
* Дата инициализации коллекции
|
||||
*/
|
||||
private final LocalDate creationDate;
|
||||
|
||||
/**
|
||||
* Конструктор без параметров, инициализирует коллекцию из файла (если есть возможность)
|
||||
* и задаёт дату инициализации
|
||||
*/
|
||||
public PersonTreeSet() {
|
||||
this.creationDate = LocalDate.now();
|
||||
if (this.file != null && this.canRead)
|
||||
this.initTreeSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, возвращающий файл для записи и чтения коллекции,
|
||||
* возвращает null если переменной окружении не существует,
|
||||
* файла не существует, файл является директорией
|
||||
* или имеет расширение, не являющееся .xml
|
||||
*
|
||||
* Устанавливает соответствующим полям {@link #canRead canRead} и {@link #canWrite canWrite} значения false,
|
||||
* если нет прав на чтение или запись
|
||||
*
|
||||
* @return Файл, если все условия соблюдены, иначе null
|
||||
*/
|
||||
public File initFile() {
|
||||
String path = System.getenv(ENV_VAR);
|
||||
if (path == null) {
|
||||
System.err.println("Переменная окружения " + ENV_VAR + " (путь к файлу) не задана, возможность сохранения и загрузки коллекции в файл отключена");
|
||||
return null;
|
||||
}
|
||||
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
System.err.println("Файла по пути " + path + " не существует, возможность сохранения и загрузки коллекции в файл отключена");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!file.isFile()) {
|
||||
System.err.println("В " + ENV_VAR + " записан путь к директории, возможность сохранения и загрузки коллекции в файл отключена");
|
||||
return null;
|
||||
}
|
||||
|
||||
String ext = this.getFileExtension(file.getPath());
|
||||
if (ext == null || !ext.equals("xml")) {
|
||||
System.err.println("Файл должен иметь расширение xml, возможность сохранения и загрузки коллекции в файл отключена");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!file.canWrite()) {
|
||||
System.err.println("Запись в этот файл невозможна, возможность сохранения коллекции файл отключена");
|
||||
this.canWrite = false;
|
||||
}
|
||||
|
||||
if (!file.canRead()) {
|
||||
System.err.println("Чтение из этого файл невозможно, возможность загрузки коллекции из файла отключена");
|
||||
this.canRead = false;
|
||||
}
|
||||
|
||||
System.out.println("Файл для сохранения и загрузки коллекции был успешно найден");
|
||||
System.out.println("Путь: " + path);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод инициализации коллекции из файла,
|
||||
* читает содержимое файла и передаёт его в метод {@link Person#peopleFromString(String)},
|
||||
* элементы полученного списка добавляются в коллекцию
|
||||
*/
|
||||
private void initTreeSet() {
|
||||
StringBuilder fileContents = new StringBuilder();
|
||||
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(this.file))) {
|
||||
int read;
|
||||
do {
|
||||
char[] buffer = new char[8192];
|
||||
read = reader.read(buffer);
|
||||
fileContents.append(buffer);
|
||||
} while (read != -1);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Не удалось инициализировать коллекцию из файла");
|
||||
return;
|
||||
}
|
||||
String contents = fileContents.toString();
|
||||
List<Person> people = Person.peopleFromString(contents);
|
||||
this.set.addAll(people);
|
||||
System.out.println("Коллекция успешно инициализирована из файла");
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, возвращающий расширение файла
|
||||
*
|
||||
* @param path Строка, в которой записан путь к файлу
|
||||
*
|
||||
* @return Расширение файла или null, если путь к файлу некорректный
|
||||
*/
|
||||
private String getFileExtension(String path) {
|
||||
String[] split = path.split("\\.", 2);
|
||||
return split.length > 1 ? split[1] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, возвращающий строку с информацией о коллекции
|
||||
*
|
||||
* @return Строка с информацией о коллекции
|
||||
*/
|
||||
public String info() {
|
||||
return String.format("Тип коллекции: %s \n" +
|
||||
"Дата инициализации: %s \n" +
|
||||
"Количество элементов: %d \n" +
|
||||
"Путь к файлу хранения: %s",
|
||||
PersonTreeSet.TYPE, this.creationDate, this.set.size(), this.file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод добавления нового элемента в коллекцию
|
||||
*
|
||||
* @param person Элемент для добавления
|
||||
*
|
||||
* @return true, если элемент был успешно добавлен, иначе false
|
||||
*/
|
||||
public boolean add(Person person) {
|
||||
return this.set.add(person);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод изменения элемента в коллекции по заданному id
|
||||
*
|
||||
* @param id Id человека, которого нужно изменить
|
||||
* @param person Элемент для добавления
|
||||
*
|
||||
* @return true, если элемент был успешно найден и изменён, иначе false
|
||||
*/
|
||||
public boolean update(long id, Person person) {
|
||||
Optional<Person> element = this.set.stream().filter(p -> p.getId() == id).findAny();
|
||||
if (element.isEmpty()) return false;
|
||||
Person p = element.get();
|
||||
p.setName(person.getName());
|
||||
p.setCoordinates(person.getCoordinates());
|
||||
p.setHeight(person.getHeight());
|
||||
p.setPassportID(person.getPassportID());
|
||||
p.setEyeColor(person.getEyeColor());
|
||||
p.setNationality(person.getNationality());
|
||||
p.setLocation(person.getLocation());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод удаления элемента из коллекции по заданному id
|
||||
*
|
||||
* @param id Id человека, которого нужно удалить
|
||||
*
|
||||
* @return true, если элемент был успешно найден и удален, иначе false
|
||||
*/
|
||||
public boolean remove(long id) {
|
||||
return this.set.removeIf(p -> p.getId() == id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод очистки коллекции
|
||||
*/
|
||||
public void clear() {
|
||||
this.set.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод сохранения коллекции в файл
|
||||
*
|
||||
* @return true, если коллекция была успешно сохранена, иначе false
|
||||
*/
|
||||
public boolean save() {
|
||||
if (file == null || !this.canWrite)
|
||||
return false;
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file))) {
|
||||
writer.write(this.toString());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод добавления элемента в коллекцию, если он больше её максимального элемента
|
||||
*
|
||||
* @param person Элемент для добавления
|
||||
*
|
||||
* @return true, если элемент был успешно добавлен, иначе false
|
||||
*/
|
||||
public boolean addIfMax(Person person) {
|
||||
Person last = this.set.last();
|
||||
if (person.compareTo(last) > 0)
|
||||
return this.set.add(person);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод добавления элемента в коллекцию, если он меньше её минимального элемента
|
||||
*
|
||||
* @param person Элемент для добавления
|
||||
*
|
||||
* @return true, если элемент был успешно добавлен, иначе false
|
||||
*/
|
||||
public boolean addIfMin(Person person) {
|
||||
Person first = this.set.first();
|
||||
if (person.compareTo(first) < 0)
|
||||
return this.set.add(person);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, складывающий рост каждого человека в коллекции
|
||||
*
|
||||
* @return Суммарный рост всех людей
|
||||
*/
|
||||
public int sumOfHeight() {
|
||||
return this.set.stream()
|
||||
.mapToInt(Person::getHeight)
|
||||
.sum();
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, фильтрующий всех людей, в имени которых имеется строка name,
|
||||
* проверка не чувствительна к регистру
|
||||
*
|
||||
* @param name Строка, по которой происходит фильтрация
|
||||
*
|
||||
* @return Список людей, в имени которых имеется строка name
|
||||
*/
|
||||
public List<Person> filterContainsName(String name) {
|
||||
return this.set.stream()
|
||||
.filter(p -> p.getName().toLowerCase(Locale.ROOT).contains(name.toLowerCase(Locale.ROOT)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод, возвращающий отсортированный по убыванию список местоположений всех людей в коллекции
|
||||
*
|
||||
* @return Отсортированный по убыванию список местоположений
|
||||
*/
|
||||
public List<Location> fieldDescendingLocation() {
|
||||
return this.set.stream()
|
||||
.map(Person::getLocation)
|
||||
.sorted(Collections.reverseOrder())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PersonTreeSet(\n" +
|
||||
this.set.stream()
|
||||
.map(p -> "\t" + p.toString())
|
||||
.collect(Collectors.joining(",\n")) +
|
||||
"\n)";
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue