Create a new "EBike application" prototype, based on a client-server (frontend, backend) architecture, with the backend designed using a layered and micro-kernel software architecture styles. The prototype:

should allow remote users and administrators to interact with the system;
should upport some level of data persistency and should make it possible: to change the persistent model and technology (e.g. MySQL, MongoDB, etc) without changing anything in the other layers;
should allow to change or add front-ends (presentation layer) without changing other layers (such as the business logic layer);
should allow to dynamically extend the set of functionalities available to users [*].
[*] this point will be refined after the lecture on Micro-Kernel architectural style.


i have this structure actually 

i copypaste all the files in one message 
package sap.ass01.bbom;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * 
 * Courteously implemented by ChatGPT 
 * 
 * prompt: 
 * 
 * "Hello ChatGPT. Could you write me a Java class 
 *  implementing a JDialog with title "Adding E-Bike", 
 *  including "OK" and "Cancel" buttons, and some input fields, 
 *  namely: an id input field (with label "E-Bike ID"), 
 *  an x input field (with label "E-Bike location - X coord:") 
 *  and an y input field (with label "E-Bike location - Y coord:"). 
 *  Thanks a lot!"
 * 
 */
public class AddEBikeDialog extends JDialog {

    private JTextField idField;
    private JTextField xCoordField;
    private JTextField yCoordField;
    private JButton okButton;
    private JButton cancelButton;
    private EBikeApp app;
    
    public AddEBikeDialog(EBikeApp owner) {
        super(owner, "Adding E-Bike", true);
        this.app = owner;
        initializeComponents();
        setupLayout();
        addEventHandlers();
        pack();
        setLocationRelativeTo(owner);
    }

    private void initializeComponents() {
        idField = new JTextField(15);
        xCoordField = new JTextField(15);
        yCoordField = new JTextField(15);
        okButton = new JButton("OK");
        cancelButton = new JButton("Cancel");
    }

    private void setupLayout() {
        JPanel inputPanel = new JPanel(new GridLayout(3, 2, 10, 10));
        inputPanel.add(new JLabel("E-Bike ID:"));
        inputPanel.add(idField);
        inputPanel.add(new JLabel("E-Bike location - X coord:"));
        inputPanel.add(xCoordField);
        inputPanel.add(new JLabel("E-Bike location - Y coord:"));
        inputPanel.add(yCoordField);

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(okButton);
        buttonPanel.add(cancelButton);

        setLayout(new BorderLayout(10, 10));
        add(inputPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);
    }

    private void addEventHandlers() {
        okButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // Implement OK button behavior here
                String id = idField.getText();
                String xCoord = xCoordField.getText();
                String yCoord = yCoordField.getText();
                app.addEBike(id, new P2d(Integer.parseInt(yCoord), Integer.parseInt(yCoord)));
                dispose();
            }
        });

        cancelButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            AddEBikeDialog dialog = new AddEBikeDialog(null);
            dialog.setVisible(true);
        });
    }
}

package sap.ass01.bbom;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * 
 * Adapted from AddEBikeDialog
 * 
 */
public class AddUserDialog extends JDialog {

    private JTextField idField;
    private JButton okButton;
    private JButton cancelButton;
    private EBikeApp app;

    public AddUserDialog(EBikeApp owner) {
        super(owner, "Adding User", true);
        app = owner;
        initializeComponents();
        setupLayout();
        addEventHandlers();
        pack();
        setLocationRelativeTo(owner);
    }

    private void initializeComponents() {
        idField = new JTextField(15);
        okButton = new JButton("OK");
        cancelButton = new JButton("Cancel");
    }

    private void setupLayout() {
        JPanel inputPanel = new JPanel(new GridLayout(3, 2, 10, 10));
        inputPanel.add(new JLabel("User ID:"));
        inputPanel.add(idField);

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(okButton);
        buttonPanel.add(cancelButton);

        setLayout(new BorderLayout(10, 10));
        add(inputPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);
    }

    private void addEventHandlers() {
        okButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // Implement OK button behavior here
                String id = idField.getText();
                app.addUser(id);                
                dispose();
            }
        });

        cancelButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            AddUserDialog dialog = new AddUserDialog(null);
            dialog.setVisible(true);
        });
    }
}

package sap.ass01.bbom;

import java.util.Optional;

public class EBike  {

	private String id;
	public enum EBikeState { AVAILABLE, IN_USE, MAINTENANCE}	
	private EBikeState state;
	private P2d loc;
	private V2d direction; 
	private double speed;
	private int batteryLevel;  /* 0..100 */
	
	public EBike(String id) {
		this.id = id;
		this.state = EBikeState.AVAILABLE;
		this.loc = new P2d(0,0);
		direction = new V2d(1,0);
		speed = 0;
	}
	
	public String getId() {
		return id;
	}

	public EBikeState getState() {
		return state;
	}
	
	public void rechargeBattery() {
		batteryLevel = 100;
		state = EBikeState.AVAILABLE;
	}
	
	public int getBatteryLevel() {
		return batteryLevel;
	}
	
	public void decreaseBatteryLevel(int delta) {
		batteryLevel -= delta;
		if (batteryLevel < 0) {
			batteryLevel = 0;
			state = EBikeState.MAINTENANCE;
		}
	}

	
	public boolean isAvailable() {
		return state.equals(EBikeState.AVAILABLE);
	}

	public void updateState(EBikeState state) {
		this.state = state;
	}
	
	public void updateLocation(P2d newLoc) {
		loc = newLoc;
	}

	public void updateSpeed(double speed) {
		this.speed = speed;
	}
	
	public void updateDirection(V2d dir) {
		this.direction = dir;
	}
	
	public double getSpeed() {
		return speed;
	}
	
	public V2d getDirection() {
		return direction;
	}
	
	public P2d getLocation(){
		return loc;
	}
	
	public String toString() {
		return "{ id: " + id + ", loc: " + loc + ", batteryLevel: " + batteryLevel + ", state: " + state + " }";
	}
	
}

package sap.ass01.bbom;

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import javax.swing.*;


public class EBikeApp extends JFrame implements ActionListener {
    
    private VisualiserPanel centralPanel;
    private JButton addUserButton, addEBikeButton, startRideButton;
    private ConcurrentHashMap<String, EBike> bikes;
    private HashMap<String, User> users;
    private HashMap<String, Ride> rides;
    
    private int rideId;
    
    public EBikeApp(){
        setupView();
        setupModel();
    }

    
    protected void setupModel() {
        bikes = new ConcurrentHashMap<String, EBike>();
        users = new HashMap<String, User>();
        rides = new HashMap<String, Ride>();
        
        rideId = 0;
        this.addUser("u1");
        this.addEBike("b1", new P2d(0,0));
    }

    protected void setupView() {
        setTitle("EBike App");        
        setSize(800,600);
        setResizable(false);
        
        setLayout(new BorderLayout());

		addUserButton = new JButton("Add User");
		addUserButton.addActionListener(this);

		addEBikeButton = new JButton("Add EBike");
		addEBikeButton.addActionListener(this);

		startRideButton = new JButton("Start Ride");
		startRideButton.addActionListener(this);
		
		JPanel topPanel = new JPanel();
		topPanel.add(addUserButton);		
		topPanel.add(addEBikeButton);		
		topPanel.add(startRideButton);		
	    add(topPanel,BorderLayout.NORTH);

        centralPanel = new VisualiserPanel(800,500,this);
	    add(centralPanel,BorderLayout.CENTER);

	    	    		
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent ev) {
				System.exit(-1);
			}
		});
    }

    public void display() {
    	SwingUtilities.invokeLater(() -> {
    		this.setVisible(true);
    	});
    }
        
    public void addEBike(String id, P2d loc) {
    	EBike bike = new EBike(id);
    	bike.updateLocation(loc);
    	bikes.put(id, bike);
    	log("added new EBike " + bike);
    	centralPanel.refresh();
    }
    
    public EBike getEBike(String id) {
    	return bikes.get(id);
    }

    public void addUser(String id) {
    	User user = new User(id);
    	user.rechargeCredit(100);
    	users.put(id, user);
    	log("added new User " + user);
    	centralPanel.refresh();
    }

    public void startNewRide(String userId, String bikeId) {
    	rideId++;    	 
    	String idRide = "ride-" + rideId;
    	
    	var b = bikes.get(bikeId);
    	var u = users.get(userId);
    	var ride = new Ride(idRide, u, b);
    	b.updateState(EBike.EBikeState.IN_USE);
    	rides.put(idRide, ride);
    	ride.start(this);
        
        log("started new Ride " + ride);        
    }

    public void endRide(String rideId) {
    	var r = rides.get(rideId);
    	r.end();
    	rides.remove(rideId);
    }
    
    public Enumeration<EBike> getEBikes(){
    	return bikes.elements();
    }
        
    public Collection<User> getUsers(){
    	return users.values();
    }
    
    public void refreshView() {
    	centralPanel.refresh();
    }
        

    @Override
	public void actionPerformed(ActionEvent e) {
        if (e.getSource() == this.addEBikeButton) {
	        JDialog d = new AddEBikeDialog(this);
	        d.setVisible(true);
        } else if (e.getSource() == this.addUserButton) {
		    JDialog d = new AddUserDialog(this);
		    d.setVisible(true);
        } else if (e.getSource() == this.startRideButton) {
	        JDialog d = new RideDialog(this);
	        d.setVisible(true);
        }
	}

	private void log(String msg) {
		System.out.println("[EBikeApp] " + msg);
	}
    
    public static class VisualiserPanel extends JPanel {
        private long dx;
        private long dy;
        private EBikeApp app;
        
        public VisualiserPanel(int w, int h, EBikeApp app){
            setSize(w,h);
            dx = w/2 - 20;
            dy = h/2 - 20;
            this.app = app;
        }

        public void paint(Graphics g){
    		Graphics2D g2 = (Graphics2D) g;
    		
    		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    		          RenderingHints.VALUE_ANTIALIAS_ON);
    		g2.setRenderingHint(RenderingHints.KEY_RENDERING,
    		          RenderingHints.VALUE_RENDER_QUALITY);
    		g2.clearRect(0,0,this.getWidth(),this.getHeight());
            
    		var it = app.getEBikes().asIterator();
    		while (it.hasNext()) {
    			var b = it.next();
    			var p = b.getLocation();
    			int x0 = (int)(dx+p.x());
		        int y0 = (int)(dy-p.y());
		        g2.drawOval(x0,y0,20,20);
		        g2.drawString(b.getId(), x0, y0 + 35);
		        g2.drawString("(" + (int)p.x() + "," + (int)p.y() + ")", x0, y0+50);
    		} 
    		
    		var it2 = app.getUsers().iterator();
    		var y = 20;
    		while (it2.hasNext()) {
    			var u = it2.next();
    			g2.drawRect(10,y,20,20);
		        g2.drawString(u.getId() + " - credit: " + u.getCredit(), 35, y+15);
		        y += 25;
    		};
            
        }
        
        public void refresh(){
            repaint();
        }
    }

	
	
	public static void main(String[] args) {
		var w = new EBikeApp();
		w.display();
	}
	
}

package sap.ass01.bbom;

/**
 *
 * 2-dimensional point
 * objects are completely state-less
 *
 */
public class P2d implements java.io.Serializable {

    private double x,y;

    public P2d(double x,double y){
        this.x=x;
        this.y=y;
    }

    public double x() {
    	return x;
    }
    
    public double y() {
    	return y;
    }
    
    public P2d sum(V2d v){
        return new P2d(x+v.x(),y+v.y());
    }

    public V2d sub(P2d v){
        return new V2d(x-v.x(),y-v.y());
    }
    
    public String toString(){
        return "P2d("+x+","+y+")";
    }

}

package sap.ass01.bbom;

import java.util.Date;
import java.util.Optional;

public class Ride {

	private Date startedDate;
	private Optional<Date> endDate;
	private User user;
	private EBike ebike;
	private boolean ongoing;
	private String id;
	private RideSimulation rideSimulation;
	
	public Ride(String id, User user, EBike ebike) {
		this.id = id;
		this.startedDate = new Date();
		this.endDate = Optional.empty();
		this.user = user;
		this.ebike = ebike;
	}
	
	public String getId() {
		return id;
	}

	public void start(EBikeApp app) {
		ongoing = true;
        rideSimulation = new RideSimulation(this, user, app);
        RideSimulationControlPanel ridingWindow = new RideSimulationControlPanel(this, app);
        ridingWindow.display();
        rideSimulation.start();
        
        
	}
	
	public void end() {
		endDate = Optional.of(new Date());
		ongoing = false;
		rideSimulation.stopSimulation();
	}

	public Date getStartedDate() {
		return startedDate;
	}

	public boolean isOngoing() {
		return this.ongoing;
	}
	
	public Optional<Date> getEndDate() {
		return endDate;
	}

	public User getUser() {
		return user;
	}

	public EBike getEBike() {
		return ebike;
	}
	
	public String toString() {
		return "{ id: " + this.id + ", user: " + user.getId() + ", bike: " + ebike.getId() + " }";
	}
}

package sap.ass01.bbom;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * Adapted from AddEBikeDialog
 * 
 */
public class RideDialog extends JDialog {

    private JTextField idEBikeField;
    private JTextField userName;
    private JButton startButton;
    private JButton cancelButton;
    private EBikeApp app;
    private String userRiding;
    private String bikeId;

    public RideDialog(EBikeApp owner) {
        super(owner, "Start Riding an EBike", true);
        initializeComponents();
        setupLayout();
        addEventHandlers();
        pack();
        setLocationRelativeTo(owner);
        app = owner;
    }

    private void initializeComponents() {
        idEBikeField = new JTextField(15);
        userName = new JTextField(15);
        startButton = new JButton("Start Riding");
        cancelButton = new JButton("Cancel");
    }

    private void setupLayout() {
        JPanel inputPanel = new JPanel(new GridLayout(3, 2, 10, 10));
        inputPanel.add(new JLabel("User name:"));
        inputPanel.add(userName);
        inputPanel.add(new JLabel("E-Bike to ride:"));
        inputPanel.add(idEBikeField);

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(startButton);
        buttonPanel.add(cancelButton);

        setLayout(new BorderLayout(10, 10));
        add(inputPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);
    }

    private void addEventHandlers() {
        startButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                bikeId = idEBikeField.getText();
	            userRiding = userName.getText();
	            cancelButton.setEnabled(false);
	            app.startNewRide(userRiding, bikeId);
	            dispose();
            }
        });
        
        cancelButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });
    }
}

package sap.ass01.bbom;

import java.util.Random;

public class RideSimulation extends Thread {
	
	private Ride ride;
	private User user;
	
	private EBikeApp app;
	private volatile boolean stopped;
	
	public RideSimulation(Ride ride, User user, EBikeApp app) {
		this.ride = ride;
		this.user = user;
		this.app = app;
		stopped = false;
	}
	
	public void run() {
		var b = ride.getEBike();
		b.updateSpeed(1);
		
		var lastTimeDecreasedCredit = System.currentTimeMillis();
		user.decreaseCredit(1);

		var lastTimeChangedDir = System.currentTimeMillis();
		
		while (!stopped) {
			
			/* update pos */
			
			var l = b.getLocation();
			var d = b.getDirection();
			var s = b.getSpeed();
			b.updateLocation(l.sum(d.mul(s)));
			l = b.getLocation();
			if (l.x() > 200 || l.x() < -200) {
				b.updateDirection(new V2d(-d.x(), d.y()));
			};
			if (l.y() > 200 || l.y() < -200) {
				b.updateDirection(new V2d(d.x(), -d.y()));
			};
			
			/* change dir randomly */
			
			var elapsedTimeSinceLastChangeDir = System.currentTimeMillis() - lastTimeChangedDir;
			if (elapsedTimeSinceLastChangeDir > 500) {
				double angle = Math.random()*60 - 30;
				b.updateDirection(d.rotate(angle));
				elapsedTimeSinceLastChangeDir = System.currentTimeMillis();
			}
			
			
			/* update credit */
			
			var elapsedTimeSinceLastDecredit = System.currentTimeMillis() - lastTimeDecreasedCredit;
			if (elapsedTimeSinceLastDecredit > 1000) {
				user.decreaseCredit(1);
				lastTimeDecreasedCredit = System.currentTimeMillis();
			}
			
			app.refreshView();

			
			try {
				Thread.sleep(20);
			} catch (Exception ex) {}
			
		}
	}

	public void stopSimulation() {
		stopped = true;
		interrupt();
	}
}

package sap.ass01.bbom;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class RideSimulationControlPanel extends JFrame {

    private JButton stopButton;
    private EBikeApp app;
    private Ride ride;

    public RideSimulationControlPanel(Ride ride, EBikeApp app) {
        super("Ongoing Ride: " + ride.getId());
    	setSize(400, 200);
        
        this.app = app;
        this.ride = ride;

        stopButton = new JButton("Stop Riding");
    	
        JPanel inputPanel = new JPanel(new GridLayout(3, 2, 10, 10));
        inputPanel.add(new JLabel("Rider name: " + ride.getUser().getId()));
        inputPanel.add(new JLabel("Riding e-bike: " + ride.getEBike().getId()));

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(stopButton);

        setLayout(new BorderLayout(10, 10));
        add(inputPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);
        
        stopButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                app.endRide(ride.getId());
        		dispose();
            }
        });
    }
    
    public void display() {
    	SwingUtilities.invokeLater(() -> {
    		this.setVisible(true);
    	});
    }

}

package sap.ass01.bbom;

public class User {

	private String id;
	private int credit;
	
	public User(String id) {
		this.id = id;
		this.credit = 0;
	}
	
	public String getId() {
		return id;
	}
	
	public int getCredit() {
		return credit;
	}
	
	public void rechargeCredit(int deltaCredit) {
		credit += deltaCredit;
	}
	
	public void decreaseCredit(int amount) {
		credit -= amount;
		if (credit < 0) {
			credit = 0;
		}
	}
	
	public String toString() {
		return "{ id: " + id + ", credit: " + credit + " }";
	}

	
}

/*
 *   V2d.java
 *
 * Copyright 2000-2001-2002  aliCE team at deis.unibo.it
 *
 * This software is the proprietary information of deis.unibo.it
 * Use is subject to license terms.
 *
 */
package sap.ass01.bbom;

/**
 *
 * 2-dimensional vector
 * objects are completely state-less
 *
 */
public class V2d implements java.io.Serializable {

    private double x,y;

    public V2d(double x,double y){
        this.x = x;
        this.y = y;
    }


    public double x() {
    	return x;
    }
    
    public double y() {
    	return y;
    }
    
    public V2d sum(V2d v){
        return new V2d(x+v.x,y+v.y);
    }
    
    public V2d rotate(double degree) {
    	var rad = degree * Math.PI/180;
    	var cs = Math.cos(rad);
    	var sn = Math.sin(rad);
    	var x1 = x * cs - y * sn;
    	var y1 = x * sn + y * cs;
    	var v = new V2d(x1, y1).getNormalized();
    	return v;
    }

    public double abs(){
        return (double)Math.sqrt(x*x+y*y);
    }

    public V2d getNormalized(){
        double module=(double)Math.sqrt(x*x+y*y);
        return new V2d(x/module,y/module);
    }

    public V2d mul(double fact){
        return new V2d(x*fact,y*fact);
    }

    public String toString(){
        return "V2d("+x+","+y+")";
    }
    
}