Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions OWNER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Максутов Айнур Мухарамович
60 changes: 58 additions & 2 deletions src/main/java/arhangel/dim/container/BeanXmlReader.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
package arhangel.dim.container;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


/**
*
Expand All @@ -14,8 +27,51 @@ public class BeanXmlReader {
private static final String ATTR_BEAN_ID = "id";
private static final String ATTR_BEAN_CLASS = "class";

public List<Bean> parseBeans(String pathToFile) {
return null;
public List<Bean> parseBeans(String pathToFile) throws InvalidConfigurationException {
System.out.print("BeanXML Parses file" + pathToFile + "\n");
List<Bean> ls = new ArrayList<>();
File file = new File(pathToFile);
if (file.exists()) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(file);
doc.getDocumentElement().normalize();
NodeList beanList = doc.getElementsByTagName(TAG_BEAN);
for (int beanIndex = 0; beanIndex < beanList.getLength(); beanIndex++) {
Node beanNode = beanList.item(beanIndex);
//System.out.print("*****\nnext Bean:\n");
Element beanEl = (Element) beanNode;
String className = beanEl.getAttribute(ATTR_BEAN_CLASS);
//System.out.print("Class: " + className + "\n");
String id = beanEl.getAttribute(ATTR_BEAN_ID);
//System.out.print("Id: " + id + "\n");
Map<String, Property> properties = new HashMap<>();
NodeList propList = ((Element) beanNode).getElementsByTagName(TAG_PROPERTY);
for (int i = 0; i < propList.getLength(); i++) {
Element propEl = (Element) (propList.item(i));
String name = propEl.getAttribute(ATTR_NAME);
String ref = propEl.getAttribute(ATTR_REF);
String val = propEl.getAttribute(ATTR_VALUE);
/*System.out.print("Property:\n");
System.out.print("Name: " + name + "\n");
System.out.print("Val: " + val + "\n");
System.out.print("Ref: " + ref + "\n");*/
if (ref != "" && val == "") {
properties.put(name, new Property(name, ref, ValueType.REF));
} else if (ref == "" && val != "") {
properties.put(name, new Property(name, val, ValueType.VAL));
}
}
ls.add(new Bean(id, className, properties));
}
} catch (ParserConfigurationException e) {
throw new InvalidConfigurationException("Problem with reading conf file");
} finally {
return ls;
}
}
return ls;
}

}
164 changes: 136 additions & 28 deletions src/main/java/arhangel/dim/container/Container.java
Original file line number Diff line number Diff line change
@@ -1,63 +1,171 @@
package arhangel.dim.container;

import arhangel.dim.container.dag.Graph;
import arhangel.dim.container.dag.Vertex;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.LinkedList;
import java.util.StringJoiner;


/**
* Используйте ваш xml reader чтобы прочитать конфиг и получить список бинов
*/
public class Container {
private List<Bean> beans;
private Map<String, Object> objByName;
private Map<String, Object> objByClass;

/**
* Если не получается считать конфиг, то бросьте исключение
* @throws InvalidConfigurationException неверный конфиг
*/
public Container(String pathToConfig) throws InvalidConfigurationException {

// вызываем BeanXmlReader
BeanXmlReader reader = new BeanXmlReader();

List<Bean> beanList = reader.parseBeans(pathToConfig);
List<Vertex<Bean>> vertexList = new ArrayList<>();
Graph<Bean> graph = new Graph<>();
Map<String, Vertex<Bean>> vertexById = new TreeMap<>();

for ( int i = 0; i < beanList.size(); i++ ) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

foreach будет читабельнее

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

У меня появились проблемы с порядком обходя foreach, поэтому пришлось воспользоваться более явным указанием порядка

Bean bean = beanList.get(i);
Vertex<Bean> vertex = graph.addVertex(bean);
vertexById.put(bean.getName(), vertex);
vertexList.add(vertex);
}

for ( int i = 0; i < vertexList.size(); i++ ) {
Vertex<Bean> vertex = vertexList.get(i);
Map<String, Property> mp = vertex.getValue().getProperties();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename mp -> propertyMap

for ( Map.Entry<String, Property> entry : mp.entrySet()) {
if ( entry.getValue().getType() == ValueType.REF ) {
String ref = entry.getValue().getValue();
System.out.print(ref + "\n");
graph.addEdge(vertex, vertexById.get(ref), true);
}
}
}
vertexList = graph.toposort();
beans = new LinkedList<>();
for ( int i = 0; i < vertexList.size(); i++ ) {
Bean bean = vertexList.get(i).getValue();
System.out.print("\nObject: \n" + bean.toString() + "\n\n");
beans.add(bean);
}
objByClass = new TreeMap<>();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А почему выбрали TreeMap?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В TreeMap(как я понял) предполагается хранение различных объектов, ну а в нашей задаче объекты различны все.
Кстати, в условии задачи сказано сделать Map для поиска объектов по классу, там предполагалось, что каждого класса будет ровно один объект?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А почему не HashMap?
Да, предаполагается, что только один объект каждого класса

objByName = new TreeMap<>();
try {
if (graph.hasCycle()) {
throw new CycleReferenceException("Here is a cicle");
} else {
for (Bean b : beans) {
preInstantiateBean(b);
}
for (Bean b : beans) {
instantiateBean(b);
}
}
} catch ( CycleReferenceException e) {
System.out.print(e.toString());
}
}

/**
* Вернуть объект по имени бина из конфига
* Например, Car car = (Car) container.getByName("carBean")
*/
public Object getByName(String name) {
return null;
return objByName.get(name);
}

/**
* Вернуть объект по имени класса
* Например, Car car = (Car) container.getByClass("arhangel.dim.container.Car")
*/
public Object getByClass(String className) {
return null;
return objByClass.get(className);
}

private void instantiateBean(Bean bean) {

/*
// Примерный ход работы
String className = bean.getClassName();
Class clazz = Class.forName(className);
// ищем дефолтный конструктор
Object ob = clazz.newInstance();
public String toString() {
StringJoiner str = new StringJoiner("\n");
for (Map.Entry e : objByName.entrySet()) {
str.add("\nObject:" + e.getKey() + " \n" + e.getValue());
}
return str.toString();
}

for (String name : bean.getProperties().keySet()) {
// ищем поле с таким именен внутри класса
// учитывая приватные
Field field = clazz.getDeclaredField(name);
// проверяем, если такого поля нет, то кидаем InvalidConfigurationException с описание ошибки
private Object fromString(String typeName, String data) throws Exception {
switch (typeName) {
case "double":
case "Double":
return Double.valueOf(data);
case "int":
case "Integer":
return Integer.valueOf(data);
case "boolean":
case "Boolean":
return Boolean.valueOf(data);
default:
throw new InvalidConfigurationException("type name = " + typeName);
}
}

// Делаем приватные поля доступными
field.setAccessible(true);
private void preInstantiateBean(Bean bean) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Зачем эта процедура? Что она улучшает?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Проблема в том, что хотя в выходном листе все классы в нормальном порядке, в порядке инициализации, почему-то , когда я прохожу его с помощью foreach, они инициализуются в другом порядке. Пришлось, чтобы не было ссылок на несуществующие объекты, сначала инициализировать все объекты без ссылок, а затем уже эти ссылки присвоить.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

То есть на самом деле, проблема в том, что бины инициализируются в неверном порядке? Может лучше решить проблему?

try {
String className = bean.getClassName();
Class clazz = Class.forName(className);
Object ob = clazz.newInstance();
objByName.put(bean.getName(), ob);
objByClass.put(bean.getClassName(), ob);
} catch (ClassNotFoundException e) {
System.out.print(e.getLocalizedMessage());
} catch (InstantiationException e) {
System.out.print(e.getLocalizedMessage());
} catch (IllegalAccessException e) {
System.out.print(e.getLocalizedMessage());
} catch (Exception e) {
System.out.print(e.getLocalizedMessage());
}
}

// Далее определяем тип поля и заполняем его
// Если поле - примитив, то все просто
// Если поле ссылка, то эта ссылка должа была быть инициализирована ранее
private void instantiateBean(Bean bean) {

*/
try {
String beanName = bean.getName();
Object ob = getByName(beanName);
Class clazz = ob.getClass();
String className = bean.getClassName();
for (String name : bean.getProperties().keySet()) {
Field field = clazz.getDeclaredField(name);
if (field == null) {
throw new InvalidConfigurationException("Failed to set field [" + name + "] for class " + clazz.getName());
}
field.setAccessible(true);
Property prop = bean.getProperties().get(name);
if (prop.getType() == ValueType.VAL) {
field.set(ob, fromString(field.getType().getTypeName(), prop.getValue()));
} else if (prop.getType() == ValueType.REF) {
if (objByName.containsKey(prop.getValue())) {
field.set(ob, getByName(prop.getValue()));
} else {
throw new InvalidConfigurationException("Failed to instantiate bean. Field " +
name + ", object: " + className + "\n");
}
}
}
} catch (ClassNotFoundException e) {
System.out.print(e.getLocalizedMessage());
} catch (InstantiationException e) {
System.out.print(e.getLocalizedMessage());
} catch (NoSuchFieldException e) {
System.out.print(e.getLocalizedMessage());
} catch (IllegalAccessException e) {
System.out.print(e.getLocalizedMessage());
} catch (Exception e) {
System.out.print(e.getLocalizedMessage());
}

}

Expand Down
17 changes: 15 additions & 2 deletions src/main/java/arhangel/dim/container/dag/Graph.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,19 @@ public int size() {
}

private LinkedList<Vertex<V>> sorted = new LinkedList<>();
private int hasCycle = 0;

public void dfs() {
sorted.clear();
hasCycle = -1;
vertices.keySet().stream().filter(vertex -> vertex.getState() != Vertex.State.VISITED).forEach(this::dfs);
}

public void dfs(Vertex<V> current) {

current.setState(Vertex.State.MARKED);
for (Vertex<V> vertex : getLinked(current)) {
if (vertex.getState() == Vertex.State.MARKED) {
hasCycle = 1;
System.out.println("Cycle: " + current + "->" + vertex);
return;
}
Expand All @@ -77,7 +80,7 @@ public void dfs(Vertex<V> current) {
}
}
current.setState(Vertex.State.VISITED);
sorted.push(current);
sorted.addLast(current);
}

public List<Vertex<V>> toposort() {
Expand All @@ -86,4 +89,14 @@ public List<Vertex<V>> toposort() {
return sorted;
}

public boolean hasCycle() {
if ( hasCycle == 0 ) {
dfs();
}
if ( hasCycle == 1 ) {
return true;
} else {
return false;
}
}
}
29 changes: 6 additions & 23 deletions src/main/java/arhangel/dim/container/dag/Main.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,18 @@
package arhangel.dim.container.dag;

import java.util.List;

import arhangel.dim.container.Container;
import arhangel.dim.container.beans.Car;

/**
*
*/
public class Main {

public static void main(String[] args) throws Exception {
Graph<Integer> graph = new Graph<>();
Vertex<Integer> v1 = graph.addVertex(1);
Vertex v2 = graph.addVertex(2);
Vertex v3 = graph.addVertex(3);
Vertex v4 = graph.addVertex(4);
Vertex v5 = graph.addVertex(5);

Vertex v6 = graph.addVertex(6);
Vertex v7 = graph.addVertex(7);


graph.addEdge(v1, v2, true);
graph.addEdge(v1, v3, true);
graph.addEdge(v2, v3, true);
graph.addEdge(v2, v4, true);
graph.addEdge(v3, v5, true);
graph.addEdge(v4, v5, true);

graph.addEdge(v6, v7, true);

List<Vertex<Integer>> sorted = graph.toposort();

Container container = new Container("./config.xml");
System.out.print(container.toString());
System.out.print("\ncarBean->gear->count = " + ((Car)container.getByName("carBean")).getGear().getCount());
}

}