java data-structure to simulate a data tree - java

I need help defining what approach to use. I have a SOAP response giving me an xml file. I need to end-up with 3 correlated lists displayed on screen. When you select one item on the first list, the corresponding choices will appear on the second list etc. I am only interested on how to organize efficiently the data after it is extracted from the xml stream. Here's an xml snippet:
<device>
<manufacturer>Acer</manufacturer>
<model>A1</model>
<platform>Android</platform>
</device>
<device>
<manufacturer>Acer</manufacturer>
<model>A1</model>
<platform>J2ME</platform>
</device>
<device>
<manufacturer>Acer</manufacturer>
<model>A2</model>
<platform>Android</platform>
</device>
<device>
<manufacturer>Samsung</manufacturer>
<model>E400</model>
<platform>Android</platform>
</device>
So, I will have something like manufacturer={"Acer", "Acer", "Acer","Samsung"}, model={"A1","A1", "A2", "E400"}, platform={"Android","J2ME","Android","Android"}.
Here comes the fun part: I need to massage the data so that I can use it to display 3 lists. After selecting Android, Acer and Samsung become available. If Acer is selected, then model A1 and A2 are available. All lists need to be sorted. Currently I'm using Sax to parse the data into a vector of objects, containing manufacturer, model, platform fields. All I can think of is a TreeMap like structure. Any suggestions would be appreciated.

I do not think that hierarchical structure is what you need here. Because user may select first platform or manufacturer. If he selects first Android you want to show 3 devices. If he selects first Acer he will see 2 devices.
So, my suggesting is the following.
create class Device with properties manufacturer, model, platform.
create a plain linked list that contains all these devices.
Create 2 maps: manufaturerIndex and plarformIndex that look like:
Map<String, Collection<Device>> manufacturerIndex;
Iterate once over the list and populate all indexes maps.
Like this:
for(Device d : devices) {
Collection<Device> selected = manufacturerIndex.get(d.getManufacturer());
if (selected == null) {
selected = new ArrayList<Device>();
manufactuerIndex.put(d.getManufacturer(), selected);
}
selected.add(d);
// the same for the second index
}
Now you can use the data structure.
manufactuerIndex.get("Nokia") -> returns all Nokia devices.
Pay attention that this data structure is extendable. You can always add as many indexes as you want.

I'd just use a sortable collection of custom objects and then filter that collection based on predicates. I am using Guava for all of this, but there are of course other (usually more complicated) ways to implement this.
Here's my Product Object:
public class Product implements Comparable<Product>{
private final String manufacturer;
private final String model;
private final String platform;
public Product(final String manufacturer,
final String model,
final String platform){
this.manufacturer = manufacturer;
this.model = model;
this.platform = platform;
}
public String getManufacturer(){
return manufacturer;
}
public String getModel(){
return model;
}
public String getPlatform(){
return platform;
}
#Override
public int hashCode(){
return Objects.hashCode(manufacturer, model, platform);
}
#Override
public boolean equals(final Object obj){
if(obj instanceof Product){
final Product other = (Product) obj;
return Objects.equal(manufacturer, other.manufacturer)
&& Objects.equal(model, other.model)
&& Objects.equal(platform, other.platform);
}
return false;
}
#Override
public int compareTo(final Product o){
return ComparisonChain
.start()
.compare(manufacturer, o.manufacturer)
.compare(model, o.model)
.compare(platform, o.platform)
.result();
}
}
Now I'd just use a TreeSet<Product> and apply views on it. Here's a sample method that returns a live view that is filtered by model:
public static Collection<Product> filterByModel(
final Collection<Product> products,
final String model){
return Collections2.filter(products, new Predicate<Product>(){
#Override
public boolean apply(final Product product){
return product.getModel().equals(model);
}
});
}
Use it like this:
Collection<Product> products = new TreeSet<Product>();
// add some products
Collection<Product> filtered = filterByModel(products, "A1");
Update: We can take it even further, using only one collection, backed by chained predicates that are in turn tied to a model backed by your view. Brain hurts? Check this out:
// this is the collection you sent to your view
final Collection<Product> visibleProducts =
Collections2.filter(products, Predicates.and(Arrays.asList(
new ManufacturerPredicate(yourViewModel),
new ModelPredicate(yourViewModel),
new PlatformModel(yourViewModel)))
);
yourViewModel is an object that is backed by the values returned from your form controller. Each predicate uses a field of this model object to decide whether it applies or not.
e.g. The ModelPredicate checks all products in the collection to see whether their model is among the selected ones. Since this uses and logic, you can make it a hierarchic structure (if the manufacturer predicate returns false, the model and platform predicates are never called).

I use nested maps for something like that. Use TreeMap to get sorted results:
TreeMap<String, TreeMap<String, Model> manufacturerMap;
TreeMap<String, Model> models = manufacturerMap.get( name );
if( models == null ) {
models = new TreeMap<String, Model>();
manufacturerMap.put( name. models );
}
... etc ...

Related

Updating ArrayLists that contains each other?

Apologies if there have been similar questions, I'm honestly not sure how to call this concept to search for questions.
So I need to create a database with 3 classes like below:
public class Actor {
private String name;
private ArrayList<Movie> movies; //all movies the actor has been in
}
public class Movie {
private String name;
private ArrayList<Actor> actors;
}
public class MovieDatabase {
private ArrayList<Movie> movieList;
private ArrayList<Actor> actorList; //all actors in the movie
}
I have to create a method to add a movie and an actor to the database.
The final goals is that the new movie needs to be of the Movie class, and contains all the actors that are in it, same for the new actor.
What I cannot figure out is that, since the Movie class contains an array of Actor objects, and the Actor class contains an array of Movie list, how do you update so that in the end, the new Movie added contains a complete list of Actors in it, with each Actor in the list having their movie lists updated with the new Movie object?
Is recursion the right concept to apply in this case?
Suppose a new Movie gets added
Movie movie = new Movies();
movie.setActors(listOfActors)
Now for each actor you need to update the movie list
listOfActors.forEach(actor -> addMovieToActor(movie,actor));
public addMovieToActor(Movie movie,Actor actor){
List<Movies> existingMovies =actor.getMovies();
existingMovies.add(movie);
}
Depending on your needs, you may need to take care of synchronization between updates.
I don't think recursion is appropriate here, although you could use it. The databases have a circular dependency so you just need to synchronize after updates. In other words, make sure that after you add a new entry, both databases are updated with the missing information. Synchronization can be made easier by swapping ArrayList out for a HashMap, you may need to refactor your classes to do this. I left out the lists for simplicity, you can add them in as a parameter:
void update(String movieName, String actorName) {
if (movies.get(movieName) == null) {
movies.put(movieName);
}
if (actors.get(actorName) == null) {
actors.put(actorName);
}
}
Use as:
HashMap<String> actors = new HashMap<>();
HashMap<String> movies = new HashMap<>();
actors.put("foo");
movies.put("bar");
// Update happened, synchronize with what you just added
update("foo", "bar");

Get elements with a certain generic type in a list

I am currently working on a train project and I have following question:
I save all rolling stock in a list:
To understand my class hierarchy better, here is a simplified inheritance overview:
RollingStock
Engine
SteamEngine
DieselEngine
...
Coach
FreightCoach
PassengerCoach
...
TrainSet
In my register, I want to save all rolling stock in a list private List<RollingStock> rollingStock;. So far, I have created a list for each rolling stock type (engines, coaches, trainSets). However, I need to delete a certain rolling stock with just its ID and therefore it's easier to save everything in just one list.
As of before, I created an engine like this:
public void createEngine(Engine engine) {
this.engines.add(engine);
}
Now, with just one list I do it like this:
public void createEngine(Engine engine) {
this.rollingStocks.add(engine);
}
This works perfectly fine. For the returnEngines() method I don't seem to find a solution:
It was as easy as this with one list for each rolling stock type:
public List<Engine> returnEngines() {
return engines;
}
Now, I have to filter all engines out of the rolling stock list:
public List<Engine> returnEngines() {
...
return rollingStock.???;
}
I could add the method public String getType() and check for its type.
I can't imagine that there isn't a better solution.
How can this be done?
Stream the list, filter for instances of Engine; map the instances from RollingStock to Engine (with a cast), collect the results into a new List. Like,
public List<Engine> returnEngines() {
return rollingStocks.stream().filter(x -> x instanceof Engine)
.map(x -> (Engine) x).collect(Collectors.toList());
}
The answer from Elliott Frisch is perfectly valid, here is a generified solution, in case you need also a method to filter your register for any type of your hierarchy:
public <T> List<T> returnClazz(Class<T> clazz) {
return rollingStocks.stream()
.filter(clazz::isInstance)
.map(clazz::cast)
.collect(Collectors.toList());
}
Which then can be used by several helper methods, e.g.
public List<TrainSet> returnTrainset() {
return returnClazz(TrainSet.class);
}
public List<Engines> returnEngines() {
return returnClazz(Engine.class);
}
...
or can be called directly.

How to map mysql enum type with hypen to JPA entity?

There's a table in mysql sakila.film which has field rating of type enum('G','PG','PG-13','R','NC-17').
I'm trying to map this in JPA entity using type enum and #Enumerated(EnumType.STRING) but not able to, as java enum doesn't allow hyphen.
Can't alter or update table also as it has lots of data and gives error -"Data truncated for column 'rating'"
How to proceed?
This sort of thing is what JPA Attribute Converters are designed to help achieve.
First you'll want to map your Java enum elements to the strings found in the database, and provide a lookup method for converting a string to an element:
public enum Rating {
G("G"), // the string arguments should exactly match what's in the database.
PG("PG"),
PG13("PG-13"),
R("R"),
NC17("NC-17");
private static final Map<String, Rating> LOOKUP = Arrays.stream(values())
.collect(Collectors.toMap(Rating::getRating, Function.identity()));
private final String rating;
Rating(final String rating) {
this.rating = rating;
}
public String getRating() {
return rating;
}
public Rating fromString(final String rating) {
// You may want to include handling for the case where the given string
// doesn't map to anything - implementation is up to you.
return LOOKUP.get(rating);
}
}
Next you're going to want a class that implements javax.persistence.AttributeConverter:
public static class RatingConverter implements AttributeConverter<Rating, String> {
#Override
public String convertToDatabaseColumn(final Rating attribute) {
return attribute.getRating();
}
#Override
public Rating convertToEntityAttribute(final String dbData) {
return Rating.fromString(dbData);
}
}
From here you need to decide whether this converter should always be applied (it sounds like it probably should be), or not.
If you want it to always be used with no further configuration from you, then annotate your converter class with #javax.persistence.Converter(autoApply = true).
If you want to choose when you use the converter, then you will need to add the annotation #javax.persistence.Convert(converter = RatingConverter.class) to the Rating attribute of each JPA entity that needs it.
Personally I usually nest the converters as a static class inside the class that they convert, but you don't have to if you'd rather keep them separate.

How do I properly write an ExtensionObject Array on an Eclipse Milo OpcUa Server?

I am trying to write an Array of ExtensionObject on an Eclipse Milo OpcUa Server.
I'm doing all this in Java 8 and on Milo 0.2.3.
My way to test what I wrote to my Server is the Unified Automation UaExpert Client and a little Python client. Both show the same results.
I have the following Structure (I named it MyStructure for this scenario). It is already present as an Array and I want to write it to the respective node.
#Getter
#Setter
#AllArgsConstructor
public class MyStructure implements UaStructure {
private String name;
private Integer dataType;
private String stringValue;
private Integer intValue;
private Float floatValue;
public static final String Description = "MyStructure ";
public static NodeId getNodeId() {
return new NodeId(2, 3081);
}
#Override
public NodeId getTypeId() {
return getNodeId();
}
#Override
public NodeId getBinaryEncodingId() {
return getNodeId();
}
#Override
public NodeId getXmlEncodingId() {
return getNodeId();
}
public static class Codec extends GenericDataTypeCodec<MyStructure > {
#Override
public Class<MyStructure > getType() {
return MyStructure .class;
}
#Override
public MyStructure decode(SerializationContext context, UaDecoder reader) {
return new MyStructure (
reader.readString("Name"),
reader.readInt32("DataType"),
reader.readString("StringValue"),
reader.readInt32("IntValue"),
reader.readFloat("FloatValue")
);
}
#Override
public void encode(SerializationContext context, MyStructure myStructure, UaEncoder writer) {
writer.writeString("Name", myStructure.getName());
writer.writeInt32("DataType", myStructure.getDataType());
writer.writeString("StringValue", myStructure.getStringValue());
writer.writeInt32("IntValue", myStructure.getIntValue());
writer.writeFloat("FloatValue", myStructure.getFloatValue());
}
}
}
I write the node like this, where node is an instance of UaVariableNode and array my Array object, which I created like this:
node.setValue(new DataValue(new Variant(array)));
Object array = Array.newInstance(MyStructure.class, myStructureList.size());
for (int i = 0; i < myStructureList.size(); i++) {
Array.set(array, i,myStructureList.get(i));
}
I registered MyStructure definition beforehand like this:
OpcUaBinaryDataTypeDictionary dictionary = new OpcUaBinaryDataTypeDictionary("mynamespace");
dictionary.registerStructCodec(
new MyStructure.Codec().asBinaryCodec(),
"MyStructure",
new NodeId(2, 3081)
);
OpcUaDataTypeManager.getInstance().registerTypeDictionary(dictionary);
Whenever I set my node, the server doesn't complain. It actually sets something, to be precise it sets 42 Extension Objects. In UaExpert I see that the value, including its timestamp, changed, but I can't see the actual value. The value is just of the type Array of ExtensionObject and I can't read any of the nested values. But that is what I saw in other projects. They have custom structures, and the nested fields are human readable in UaExpert.
The problem doesn't change if I do it without the Array and just write one MyStructure.
Do you have an idea, what I am doing wrong or not doing at all?
Right now custom structures in Milo only work if the client reading/writing them knows about the structure in advance.
What you're missing (and isn't implemented by Milo yet) is all the complexity around creating a DataTypeDictionary, registering it in the address space, and linking your codec to an entry in that dictionary via a DataTypeEncoding.
If you were to use a tool like UaModeler and create a custom structure in it, then take a look at the generated XML, you'd see there's a whole bunch of other supporting nodes that go along with it.
When these things are in place, clients can learn how to decode custom structures without knowing about them in advance. Milo's client includes this functionality as well.
Also, fwiw, you should encode your array of structures by making an ExtensionObject[], with each ExtensionObject holding one scalar structure value.

Creating Object List in Java class - better approach

A have a question related to creating object list in Java class.
Can someone tell me which solution is better? Pros and cons of it?
1) My first version of class:
public class ProductRepositoryImpl implements ProductRepository {
private List<Product> listOfProducts = new ArrayList<Product>();
public ProductRepositoryImpl() {
addProducts(1, "Silnik", "Ferrari", 1000, listOfProducts);
addProducts(2, "Sprzęgło", "Opel", 500, listOfProducts);
addProducts(3, "Kierownica", "Fiat", 100, listOfProducts);
addProducts(4, "Panewka", "Maluch", 250.00, listOfProducts);
addProducts(5, "Akumulator", "Autosan", 1700.00, listOfProducts);
addProducts(6, "Zakrętka", "Maseratii", 100.00, listOfProducts);
}
private void addProducts(int idProduct, String name, String brand, double price, List list) {
Product product = new Product();
product.setId(idProduct);
product.setName(name);
product.setBrand(brand);
product.setPrice(price);
list.add(product);
}
#Override
public List<Product> getListOfProducts() {
return listOfProducts;
}
}
2) And the second one:
public class ProductRepositoryImpl implements ProductRepository {
private List<Product> listOfProducts = new ArrayList<Product>();
public ProductRepositoryImpl() {
Product p1 = new Product();
p1.setId(1);
p1.setName("Silnik");
p1.setBrand("Ferrari");
p1.setPrice(1000);
Product p2 = new Product();
p2.setId(2);
p2.setName("Hamulec");
p2.setBrand("Opel");
p2.setPrice(500);
Product p3 = new Product();
p3.setId(3);
p3.setName("Kierownica");
p3.setBrand("Fiat");
p3.setPrice(100);
Product p4 = new Product();
p4.setId(4);
p4.setName("Akumulator");
p4.setBrand("Autosan");
p4.setPrice(1700);
Product p5 = new Product();
p5.setId(5);
p5.setName("Zakrętka");
p5.setBrand("Maseratii");
p5.setPrice(100);
listOfProducts.add(p1);
listOfProducts.add(p2);
listOfProducts.add(p3);
listOfProducts.add(p4);
listOfProducts.add(p5);
}
#Override
public List<Product> getListOfProducts() {
return listOfProducts;
}
}
I will be grateful for every explaination.
There are some design guide lines which will help you in improving your code :
Separation of responsibilities. ProductRepositoryImpl should be responsible for dealing with a repository of products. It is not its responsibility and should not have code for constructing Products. Construction of products should be the responsibility of Product
Code reuse. Version 1 is better than version 2 since the code for construction of a product is written once, inside addProducts(), rather than multiple times as in version 2.
Encapsulation. The interface of a class is the only part which should be public. It's implementation should be hidden. This means that the id field of a product should not be directly accesed from the outside, but instead should be accesed through interface methods. The advantage being that if you later on need to change how ids internally work you can do it easily because all ids come and go from a few methods in the Product class. If the id field is public then there may be hundreds of places accessing it and dealing with such a change would be a nightmare.
Another issue is mutability. Your Product class is mutable, as implied by the setName method. If that is an absolute requirement of your application go ahead. But if a product does not change once defined you should rather make Product inmutable. Inmutability has several advantages, one of them being that it is thread safe without needing synchronization. So I have made Product inmutable.
With those guide lines in mind this is the approach I would take :
class Product
{
private final int idProduct;
private final String name;
private final String brand;
private final double price;
public Product(int idProduct, String name, String brand, double price)
{
this.idProduct = idProduct;
this.name = name;
this.brand = brand;
this.price = price;
}
}
public class ProductRepositoryImpl implements ProductRepository
{
private List<Product> listOfProducts = new ArrayList<Product>();
public ProductRepositoryImpl()
{
addProduct(new Product(1, "Silnik", "Ferrari", 1000));
addProduct(new Product(2, "Sprzęgło", "Opel", 500));
addProduct(new Product(3, "Kierownica", "Fiat", 100));
addProduct(new Product(4, "Panewka", "Maluch", 250.00));
addProduct(new Product(5, "Akumulator", "Autosan", 1700.00));
addProduct(new Product(6, "Zakrętka", "Maseratii", 100.00));
}
private void addProduct(Product product)
{
listOfProducts.add(product);
}
#Override
public List<Product> getListOfProducts()
{
return listOfProducts;
}
}
The first option denotes a Factory and is usually recommended.
The reason why it is recommended is because object initialization is localized to one central place, thus if you need to perform any extra checks before the initialization, such design would ensure that you need only make changes to one portion of the code.
As a side note, in the example you posted, it woon't really make much of a difference since should the structure of the object change, you would only need to add an extra setter instead of passing an extra parameter.
However, in other scenarios object creation would depend on other objects. Thus, the pattern would allow you to make the least amount of changes, thus reducing the chances of introducing new bugs in the code because you forgot to update that one line burried somewhere in your code.
Also as it has been pointed out in the comments, addProducts should really become addProduct, since it is adding only one item.
In general the first design is better. It reduces code duplication. On the other hand you can improve it further.
It seems that your object stores only hardcoded values. You should consider moving this code into .property files
Returning immutable version of your list. It might prevent some unpleasant surprises
If you want to perceive this object as a true repository you should provide method which will have some fetching method by specification/filter. Currently it does not provide encapsulation.

Categories

Resources