% ! TeX program = lualatex \documentclass[a4paper,11pt]{article} % packages \usepackage{censor} \StopCensoring \usepackage{fontspec} \setmainfont{EB Garamond} % for tironian et fallback % % \directlua{luaotfload.add_fallback % % ("emojifallback", % % {"Noto Serif:mode=harf"} % % )} % % \setmainfont{EB Garamond}[RawFeature={fallback=emojifallback}] \setmonofont[Scale=MatchLowercase]{Deja Vu Sans Mono} \usepackage[a4paper,left=2cm,right=2cm,top=\dimexpr15mm+1.5\baselineskip,bottom=2cm]{geometry} \setlength{\parindent}{0pt} \usepackage{fancyhdr} % Headers and footers \fancyhead[R]{\normalfont \leftmark} \fancyhead[L]{} \pagestyle{fancy} \usepackage{microtype} % Slightly tweak font spacing for aesthetics \usepackage[english]{babel} % Language hyphenation and typographical rules \usepackage{xcolor} \definecolor{linkblue}{RGB}{0, 64, 128} \usepackage[final, colorlinks = false, urlcolor = linkblue]{hyperref} % \newcommand{\secref}[1]{\textbf{§~\nameref{#1}}} \newcommand{\secref}[1]{\textbf{§\ref{#1}~\nameref{#1}}} \usepackage{changepage} % adjust margins on the fly \usepackage{amsmath,amssymb} \usepackage{minted} \usemintedstyle{algol_nu} \usepackage{pgfplots} \pgfplotsset{width=\textwidth,compat=1.9} \usepackage{caption} \newenvironment{code}{\captionsetup{type=listing}}{} \captionsetup[listing]{skip=0pt} \setlength{\abovecaptionskip}{5pt} \setlength{\belowcaptionskip}{5pt} \usepackage[yyyymmdd]{datetime} \renewcommand{\dateseparator}{--} \usepackage{enumitem} \usepackage{titlesec} \author{Andrew Hayes} \begin{document} \begin{titlepage} \begin{center} \hrule \vspace*{0.6cm} \Huge \textsc{ct414} \vspace*{0.6cm} \hrule \LARGE \vspace{0.5cm} Distributed Systems \& Co-Operative Computing \vspace{0.5cm} \hrule \vfill \hrule \begin{minipage}{0.495\textwidth} \vspace{0.4em} \raggedright \normalsize \begin{tabular}{@{}l l} Name: & Andrew Hayes \\ Student ID: & 21321503 \\ E-mail: & \href{mailto://a.hayes18@universityofgalway.ie}{a.hayes18@universityofgalway.ie} \\ \end{tabular} \end{minipage} \begin{minipage}{0.495\textwidth} \raggedleft \vspace*{0.8cm} \Large \today \vspace*{0.6cm} \end{minipage} \medskip\hrule \end{center} \end{titlepage} \pagenumbering{roman} \newpage \tableofcontents \newpage \setcounter{page}{1} \pagenumbering{arabic} \section{Introduction} \subsection{Client-Server Architectures} \subsubsection{Two-Tier Architectures} A \textbf{two-tier client-server architecture} is a client-server architecture wherein a client talks directly to a server, with no intervening server. It is typically used in small environments ($\lesssim$ 50 users). \\\\ A common development error is to prototype an application in a small, two-tier environment, and then scale up by simply adding more users to the server: this approach will usually result in an ineffective system, as the server becomes overwhelmed. To properly scale to hundreds or thousands of users, it is usually necessary to move to a three-tier architecture. \begin{figure}[H] \centering \includegraphics[width=0.7\textwidth]{./images/client-server-tcpip.png} \caption{ Client \& server using TCP/IP protocols to communicate. Information can flow in either or both directions. The client \& server can interact with a transport layer protocols. } \end{figure} \subsection{Three-Tier Architecture} A \textbf{three-tier client-server architecture} introduces a server or \textbf{agent} (or \textbf{load-balancer}) between the client \& the server. The agent has many roles: \begin{itemize} \item Translation services: such as adapting a legacy application on a mainframe to a client-server environment. \item Metering services: such as acting as a transaction monitor to limit the number of simultaneous requests to a given server. \item Intelligent agent services: as in mapping a request to a number of different servers, collating the results, and returning a single response to the client. \end{itemize} \subsection{Network Programming Paradigms} Practically all network programming is based on a client-server model; the only real difference in paradigms is the \textbf{level} at which the programmer operates. The sockets API provides direct access to the available transport layer protocols. RPC is a higher-level abstraction that hides some of the lower-level complexities. Other approaches are also possible: \begin{itemize} \item Sockets are probably the best-known and most widely-used paradigm. However, problems of data incompatibility across platforms can arise. \item RPC libraries aim to solve some of the basic problems with sockets and provide a level of transport independence. \item Neither approach works very well with modern applications (Java RMI and other mdoern technologies, e.g., web services are better). \end{itemize} \section{Java RMI} \textbf{Remote Method Invocation (RMI)} is a Java-based mechanism for distributed object computing. RMI enables the distribution of work to other Java objects residing in other processes or on other machines. The objects in one Java Virtual Machine (JVM) are allowed to seamlessly invoke methods on objects in a remote JVM. To call a method of a remote object, we must first get a reference to that object, which can be obtained from the registry name facility or by receiving the reference as an argument or return value of a method call. Clients can call a remote object in a server that itself is a client of another server. Parameters of method calls are passed as serialised objects: \begin{itemize} \item types are not truncated, and therefore, object-oriented polymorphism is supported; \item parameters are passed by value (deep copy) and therefore object behaviour can be passed. \end{itemize} The Java Object Model is still supported with distributed (remote) objects. A reference to a remote object can be passed to or returned from local \& remote objects. Remote object references are passed by reference: therefore, the whole object is not always downloaded. Objects that implement the \mintinline{java}{Remote} interface are passed as a remote reference, while other objects are passed by value (using object serialisation). \begin{figure}[H] \centering \includegraphics[width=0.8\textwidth]{./images/javarmi.png} \caption{Java RMI Architecture} \end{figure} The client obtains a reference for a remote object by calling \mintinline{java}{Naming.lookup(//URL/registered_name)} which is a method which returns a reference to another remote object. Methods of the remote object may then be called by the client. This call is actually to the \textbf{stub} which represents the remote object. The stub packages the arguments (\textbf{marshalling}) into a data stream (to be sent across the network). On the implementation side, the skeleton unmarshals the argument, calls the method, marshals the return value, and sends it back. The stub unmarshals the return value and returns it to the caller. The RMI layer sits on top of the JVM and this allows it to use Java Garbage Collection of remote objects, Java Security (a security manager may be set for the server, now deprecated), and Java class loading. \subsection{Steps to Creating an RMI Application} \begin{enumerate} \item Define the interfaces to your remote objects. \item Implement the remote object classes. \item Write the main client \& server programs. \item Create the stub \& skeleton classes by running the \textit{rmic} compiler on the remote implementation classes. (No longer needed in later Java versions). \item Start the \textit{rmiregistry} (if not already started). \item Start the server application. \item Start the client (which contains some initial object references). \item The client application/applet may then call object methods in the remote (server) program. \end{enumerate} \subsection{Example Java RMI Program} \begin{code} \begin{minted}[linenos, breaklines, frame=single]{java} // Remote Object has a single method that is passed // the name of a country and returns the capital city. import java.rmi.*; public interface CityServer extends Remote { String getCapital(String Country) throws RemoteException; } \end{minted} \caption{Example Java RMI Program} \end{code} \begin{code} \begin{minted}[linenos, breaklines, frame=single]{java} import java.rmi.*; import java.rmi.server.*; public class CityServerImpl extends UnicastRemoteObject implements CityServer { // constructor is required in RMI CityServerImpl() throws RemoteException { super(); // call the parent constructor } // Remote method we are implementing! public String getCapital(String country) throws RemoteException { System.out.println("Sending return string now - country requested: " + country); if (country.toLowerCase().compareTo("usa") == 0) return "Washington"; else if (country.toLowerCase().compareTo("ireland") == 0) return "Dublin"; else if (country.toLowerCase().compareTo("france") == 0) return "Paris"; return "Don't know that one!"; } // main is required because the server is standalone public static void main(String args[]) { try { // First reset our Security manager System.setSecurityManager(new RMISecurityManager()); System.out.println("Security manager set"); // Create an instance of the local object CityServerImpl cityServer = new CityServerImpl(); System.out.println("Instance of City Server created"); // Put the server object into the Registry Naming.rebind("Capitals", cityServer); System.out.println("Name rebind completed"); System.out.println("Server ready for requests!"); } catch(Exception exc) { System.out.println("Error in main - " + exc.toString()); } } } \end{minted} \caption{Example Server Implementation} \end{code} \begin{code} \begin{minted}[linenos, breaklines, frame=single]{java} public class CityClient { public static void main (String args[]) { CityServer cities = (CityServer) Naming.lookup("//localhost/Capitals"); try { String capital = cities.getCapital("USA"); System.out.println(capital); } catch (Exception e) {} } } \end{minted} \caption{Example Client Implementation} \end{code} No distributed system can mask communication failures: method semantics should include failure possibilities. Every RMI remote method must declare the exception \mintinline{java}{RemoteException} in its \mintinline{java}{throw} clause. This exception is thrown when method invocation or return fails. The Java compiler requires the failures to be handled. \\\\ When implementing a remote object, the implementation class usually extends the RMI class \mintinline{java}{UnicastRemoteObject}: this indicates that the implementation class is used to create a single (non-replicated) remote object that uses RMI's default sockets-based transport for communication. If you choose to extend a remote object from a non-remote class, you need to explicitly export the remote object by calling the method \mintinline{java}{UnicastRemoteObject.exportObject()}. \\\\ The main method of the service first needs to create \& install a \textbf{security manager}, either the \mintinline{java}{RMISecurityManager} or one that you have defined yourself. A security manager needs to be running so that it can guarantee that the classes loaded do not perform ``sensitive'' operations. If no security manager is specified, no class loading for RMI classes is allowed, local or otherwise. \\\\ TO make classes available via a web server (or your classpath), copy them into your public HTML directory. Alternatively, you could have compiled your files directly into your public HTML directory: \begin{minted}[linenos, breaklines, frame=single]{shell} javac -d ~/project_dir/public_html City*.java rmic -d ~/project_dir/public_html CityServerImpl \end{minted} The files generated by \mintinline{shell}{rmic} (in this case) are: \verb|CityServerImpl_Stub.class| \& \verb|CityServerImpl_Skel.class|. \\\\ \textbf{Polymorphic distributed computing} is the ability to recognise (at runtime) the actual implementation type of a particular interface. We will use the example of a remote object that is used to computer arbitrary tasks: \begin{itemize} \item Client sends task object to compute server. \item Compute server runs task and returns result. \item RMI loads task code dynamically in the server. \end{itemize} This example shows polymorphism on the server, but it also works on the client, for example the server returns a particular interface implementation. \end{document}