package sale;
import java.util.*;
import java.io.*;
import javax.swing.*;
import java.awt.Rectangle;
import java.awt.event.*;
import users.*;
import log.*;
import sale.multiwindow.*;
import sale.events.*;
import data.NameContext;
import data.NameContextException;
import data.DataBasket;
import data.Stock;
import data.Catalog;
import data.DuplicateKeyException;
import util.*;
public class Shop extends Object implements SerializableListener {
private static class DisplayFrame extends JDisplayFrame {
private SalesPoint m_spOwner;
public DisplayFrame (SalesPoint spOwner) {
super();
m_spOwner = spOwner;
}
protected void exitForm() {
new Thread("Salespoint closer") {
public void run() {
m_spOwner.quit();
}
}.start();
}
protected void formSheetClosed() {}
}
protected List m_lspSalesPoints = new LinkedList();
private transient Object m_oSalesPointsLock;
protected final Object getSalesPointsLock() {
if (m_oSalesPointsLock == null) {
m_oSalesPointsLock = new Object();
}
return m_oSalesPointsLock;
}
private SalesPoint m_spCurrent = null;
private int m_nCurrentSalesPointIsAdjusting = 0;
protected Rectangle m_rShopFrameBounds = null;
protected static class ProcessHandle implements ProcessContext {
protected SaleProcess m_p;
protected Display m_d = NullDisplay.s_ndGlobal;
protected User m_usr;
protected DataBasket m_db;
public ProcessHandle (SaleProcess p,
Display d,
User usr,
DataBasket db) {
super();
if (d != null) {
m_d = d;
}
m_usr = usr;
m_p = p;
m_p.attach (db);
m_p.attach (this);
}
public void setFormSheet(SaleProcess p, FormSheet fs)
throws InterruptedException {
if (fs != null) {
fs.attach (p);
}
m_d.setFormSheet (fs);
}
public void popUpFormSheet(SaleProcess p, FormSheet fs)
throws InterruptedException {
if (fs != null) {
fs.attach (p);
}
m_d.popUpFormSheet (fs);
}
public void setMenuSheet(SaleProcess p, MenuSheet ms) {
if (ms != null) {
ms.attach (p);
}
m_d.setMenuSheet (ms);
}
public boolean hasUseableDisplay (SaleProcess p) {
return m_d.isUseableDisplay();
}
public void log (SaleProcess p, Loggable la)
throws IOException {
Shop.getTheShop().log (la);
}
public User getCurrentUser(SaleProcess p) {
return m_usr;
}
public Stock getStock (String sName) {
return Shop.getTheShop().getStock (sName);
}
public Catalog getCatalog (String sName) {
return Shop.getTheShop().getCatalog (sName);
}
public void processStarted (SaleProcess p) {}
public void processFinished (SaleProcess p) {
p.detachContext();
synchronized (Shop.getTheShop().getProcessesLock()) {
Shop.getTheShop().m_lphProcesses.remove (this);
}
}
public void suspend()
throws InterruptedException {
m_p.suspend();
}
public void resume() {
m_p.resume();
}
public boolean canShutdown (boolean fContextDestroy) {
return m_p.canQuit (fContextDestroy);
}
}
protected List m_lphProcesses = new LinkedList();
private transient Object m_oProcessesLock;
protected final Object getProcessesLock() {
if (m_oProcessesLock == null) {
m_oProcessesLock = new Object();
}
return m_oProcessesLock;
}
private Map m_mpCatalogs = new HashMap();
private transient Object m_oCatalogsLock;
private final Object getCatalogsLock() {
if (m_oCatalogsLock == null) {
m_oCatalogsLock = new Object();
}
return m_oCatalogsLock;
}
private final NameContext m_ncCatalogContext = new NameContext() {
public void checkNameChange (DataBasket db, String sOldName, String sNewName)
throws NameContextException {
if (db != null) {
throw new NameContextException ("Rollback/commit of name changes of global Catalogs not yet implemented.");
}
if (m_mpCatalogs.containsKey (sNewName)) {
throw new NameContextException ("Name already spent!");
}
}
public void nameHasChanged (DataBasket db, String sOldName, String sNewName) {
m_mpCatalogs.put (sNewName, m_mpCatalogs.remove (sOldName));
}
public Object getNCMonitor() {
return getCatalogsLock();
}
};
private Map m_mpStocks = new HashMap();
private transient Object m_oStocksLock;
private final Object getStocksLock() {
if (m_oStocksLock == null) {
m_oStocksLock = new Object();
}
return m_oStocksLock;
}
private final NameContext m_ncStockContext = new NameContext() {
public void checkNameChange (DataBasket db, String sOldName, String sNewName)
throws NameContextException {
if (db != null) {
throw new NameContextException ("Rollback/commit of name changes of global Stocks not yet implemented.");
}
if (m_mpStocks.containsKey (sNewName)) {
throw new NameContextException ("Name already spent!");
}
}
public void nameHasChanged (DataBasket db, String sOldName, String sNewName) {
m_mpStocks.put (sNewName, m_mpStocks.remove (sOldName));
}
public Object getNCMonitor() {
return getStocksLock();
}
};
private int m_nShopState = DEAD;
private transient Object m_oStateLock;
private final Object getStateLock() {
if (m_oStateLock == null) {
m_oStateLock = new Object();
}
return m_oStateLock;
}
protected transient JFrame m_jfShopFrame = null;
protected String m_sShopFrameTitle = "Shop";
private transient MenuSheet m_msMultiWindowMenu;
protected Timer m_trTimer;
protected Map m_mpToPersistify = new HashMap();
private transient Object m_oPersistifyLock = null;
private final Object getPersistifyLock() {
if (m_oPersistifyLock == null) {
m_oPersistifyLock = new Object();
}
return m_oPersistifyLock;
}
private void writeObject (ObjectOutputStream oos) throws IOException {
util.Debug.print ("Writing Shop!", -1);
synchronized (getPersistifyLock()) {
oos.defaultWriteObject();
}
onSaveFrames (oos);
util.Debug.print ("Finished writing Shop.", -1);
}
private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException {
util.Debug.print ("Loading Shop...", -1);
setTheShop (this);
synchronized (getPersistifyLock()) {
ois.defaultReadObject();
}
onLoadFrames (ois);
util.Debug.print ("Finished loading Shop.", -1);
}
protected Shop() {
}
public void addSalesPoint (final SalesPoint sp) {
synchronized (getStateLock()) {
if (getShopState() != RUNNING) {
try {
sp.suspend();
}
catch (InterruptedException e) {}
}
synchronized (getSalesPointsLock()) {
JDisplayFrame jdf = new DisplayFrame (sp);
jdf.setFrameTitlePrefix (sp.getName());
sp.attach (jdf);
sp.attachStatusDisplay (createStatusDisplay (sp));
if (sp.getSalesPointFrameBounds() != null) {
jdf.setBounds (sp.getSalesPointFrameBounds());
}
if (getShopState() == RUNNING) {
jdf.setVisible (true);
}
m_lspSalesPoints.add (sp);
onSalesPointAdded (sp);
}
}
}
protected void onSalesPointAdded (final SalesPoint sp) {
MenuSheet ms = ((MultiWindow) getShopFrame()).getCurrentMenuSheet();
if (ms != null) {
ms = (MenuSheet) ms.getTaggedItem (SET_CURRENT_SP_TAG);
if (ms != null) {
ms.add (new MenuSheetItem (sp.getName(), "__TAG:_SALESPOINT_SELECTOR_" + sp.getName(), new Action() {
public void doAction (SaleProcess p, SalesPoint _sp) throws IOException {
Shop.getTheShop().setCurrentSalesPoint (sp);
}
}));
}
}
setCurrentSalesPoint (sp);
sp.logSalesPointOpened();
}
public void removeSalesPoint (SalesPoint sp) {
try {
sp.suspend();
}
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
synchronized (getSalesPointsLock()) {
JDisplayFrame jdf = (JDisplayFrame) sp.detachDisplay();
jdf.dispose();
removeStatusDisplay (sp.detachStatusDisplay());
m_lspSalesPoints.remove (sp);
onSalesPointRemoved (sp);
}
}
protected void onSalesPointRemoved (SalesPoint sp) {
if (getCurrentSalesPoint() == sp) {
if (m_lspSalesPoints.size() > 0) {
setCurrentSalesPoint ((SalesPoint) m_lspSalesPoints.get (0));
}
else {
setCurrentSalesPoint (null);
}
}
MenuSheet ms = ((MultiWindow) getShopFrame()).getCurrentMenuSheet();
if (ms != null) {
ms = (MenuSheet) ms.getTaggedItem (SET_CURRENT_SP_TAG);
if (ms != null) {
ms.remove ("__TAG:_SALESPOINT_SELECTOR_" + sp.getName());
}
}
sp.logSalesPointClosed();
}
protected Display createStatusDisplay (SalesPoint sp) {
MultiWindowHandle mwh = (MultiWindowHandle) ((MultiWindow) getShopFrame()).getNewHandle();
mwh.setDisplayCaption (sp.getName());
((MultiWindow) getShopFrame()).makeVisible (mwh);
return mwh;
}
protected void removeStatusDisplay (Display d) {
((MultiWindow) getShopFrame()).closeDisplay (d);
}
public List getSalesPoints() {
synchronized (getSalesPointsLock()) {
return Collections.unmodifiableList (m_lspSalesPoints);
}
}
public void setCurrentSalesPoint (SalesPoint sp) {
if (isCurrentSalesPointAdjusting()) {
return;
}
JDisplayFrame jdf = (JDisplayFrame) sp.getDisplay();
jdf.toFront();
}
public void setCurrentSalesPointIsAdjusting() {
++m_nCurrentSalesPointIsAdjusting;
}
public void resetCurrentSalesPointIsAdjusting() {
--m_nCurrentSalesPointIsAdjusting;
}
public boolean isCurrentSalesPointAdjusting() {
return m_nCurrentSalesPointIsAdjusting > 0;
}
public SalesPoint getCurrentSalesPoint() {
return m_spCurrent;
}
public void runProcess (SaleProcess p,
Display d,
User usr,
DataBasket db) {
synchronized (getStateLock()) {
synchronized (getProcessesLock()) {
m_lphProcesses.add (new ProcessHandle (p, d, usr, db));
if (getShopState() == RUNNING) {
p.start();
}
else {
try {
p.suspend();
}
catch (InterruptedException ie) {}
}
}
}
}
public void runBackgroundProcess (SaleProcess p,
User usr,
DataBasket db) {
runProcess (p, null, usr, db);
}
public void start() {
synchronized (getStateLock()) {
if (getShopState() == DEAD) {
JFrame jf = getShopFrame();
if (getShopFrameBounds() != null) {
jf.setBounds (getShopFrameBounds());
}
else {
jf.pack();
}
jf.setVisible (true);
m_nShopState = SUSPENDED;
resume();
}
}
}
public void setShopFrameBounds (Rectangle r) {
if (getShopState() == DEAD) {
m_rShopFrameBounds = r;
}
else {
if ((m_rShopFrameBounds != null) && (getShopState() == RUNNING)) {
m_rShopFrameBounds = r;
getShopFrame().setBounds (r);
getShopFrame().hide();
getShopFrame().show();
}
}
}
public Rectangle getShopFrameBounds() {
return m_rShopFrameBounds;
}
public void suspend() {
synchronized (getStateLock()) {
if (getShopState() == RUNNING) {
synchronized (getProcessesLock()) {
for (Iterator i = m_lphProcesses.iterator(); i.hasNext();) {
try {
((ProcessHandle) i.next()).suspend();
}
catch (InterruptedException ie) {}
}
}
synchronized (getSalesPointsLock()) {
for (Iterator i = m_lspSalesPoints.iterator(); i.hasNext();){
try {
((SalesPoint) i.next()).suspend();
}
catch (InterruptedException e) {}
}
}
m_nShopState = SUSPENDED;
}
}
}
public void resume() {
synchronized (getStateLock()) {
if (getShopState() == SUSPENDED) {
synchronized (getProcessesLock()) {
for (Iterator i = m_lphProcesses.iterator(); i.hasNext();) {
((ProcessHandle) i.next()).resume();
}
}
synchronized (getSalesPointsLock()) {
for (Iterator i = m_lspSalesPoints.iterator(); i.hasNext();){
SalesPoint sp = (SalesPoint) i.next();
JDisplayFrame jdf = (JDisplayFrame) sp.getDisplay();
jdf.setVisible (true);
sp.resume();
}
}
m_nShopState = RUNNING;
}
}
}
public void quit() {
if (Shop.getTheShop().shutdown (true)) {
System.exit (0);
};
}
public boolean shutdown (boolean fPersistify) {
synchronized (getSalesPointsLock()) {
synchronized (getProcessesLock()) {
boolean fRunning = (getShopState() == RUNNING);
if (!canShutdown (fPersistify)) {
return false;
}
if (fPersistify) {
try {
makePersistent();
}
catch (CancelledException ce) {
if (fRunning) {
resume();
}
return false;
}
catch (Throwable t) {
System.err.println ("Exception occurred while making persistent: " + t);
t.printStackTrace();
if (fRunning) {
resume();
}
return false;
}
}
clearInternalStructures();
m_nShopState = DEAD;
return true;
}
}
}
protected boolean canShutdown (boolean fPersistify) {
boolean fRunning = (getShopState() == RUNNING);
if (fRunning) {
suspend();
}
boolean fCanQuit = true;
for (Iterator i = m_lphProcesses.iterator(); i.hasNext() && fCanQuit;) {
fCanQuit = ((ProcessHandle) i.next()).canShutdown (!fPersistify);
}
for (Iterator i = m_lspSalesPoints.iterator(); i.hasNext() && fCanQuit;){
fCanQuit = ((SalesPoint) i.next()).canQuit (!fPersistify);
}
if (!fCanQuit) {
if (fRunning) {
resume();
}
return false;
}
return true;
}
public int getShopState() {
return m_nShopState;
}
public synchronized void makePersistent() throws IOException, CancelledException {
boolean fRunning = (getShopState() == RUNNING);
if (fRunning) {
suspend();
}
try {
OutputStream osStream = retrievePersistanceOutStream();
synchronized (getSalesPointsLock()) {
synchronized (getProcessesLock()) {
ObjectOutputStream oosOut = new ObjectOutputStream (osStream);
oosOut.writeObject (this);
oosOut.writeObject (UserManager.getGlobalUM());
oosOut.writeObject (User.getGlobalPassWDGarbler());
oosOut.flush();
oosOut.close();
osStream.close();
}
}
}
finally {
if (fRunning) {
resume();
}
}
}
protected void onSaveFrames (ObjectOutputStream oos) throws IOException {
((MultiWindow) getShopFrame()).save (oos);
for (Iterator i = m_lspSalesPoints.iterator(); i.hasNext();) {
((JDisplayFrame) ((SalesPoint) i.next()).getDisplay()).save (oos);
}
}
public synchronized void restore() throws IOException, ClassNotFoundException, CancelledException {
InputStream isStream = retrievePersistanceInStream();
if (!shutdown (false)) {
throw new CancelledException();
}
synchronized (getSalesPointsLock()) {
synchronized (getProcessesLock()) {
ObjectInputStream oisIn = new ObjectInputStream (isStream);
oisIn.readObject();
UserManager.setGlobalUM ((UserManager) oisIn.readObject());
User.setGlobalPassWDGarbler ((users.PassWDGarbler) oisIn.readObject());
oisIn.close();
isStream.close();
}
}
synchronized (getTheShop().getStateLock()) {
getTheShop().m_nShopState = SUSPENDED;
getTheShop().resume();
}
}
protected void onLoadFrames (ObjectInputStream ois) throws IOException, ClassNotFoundException {
((MultiWindow) getShopFrame()).load (ois);
for (Iterator i = m_lspSalesPoints.iterator(); i.hasNext();) {
SalesPoint sp = (SalesPoint) i.next();
JDisplayFrame jdf = new DisplayFrame (sp);
jdf.load (ois);
sp.attachLoadedDisplay (jdf);
}
}
private JFileChooser getChooser() {
JFileChooser jfcChooser = new JFileChooser();
jfcChooser.setFileFilter (new javax.swing.filechooser.FileFilter() {
public boolean accept (File fToAccept) {
if (fToAccept == null) return false;
if (fToAccept.isDirectory()) return true;
StringTokenizer stName = new StringTokenizer (fToAccept.getName(), ".");
if (stName.hasMoreTokens()) stName.nextToken();
else return false;
String sSuffix = null;
while (stName.hasMoreTokens()) {
sSuffix = stName.nextToken();
}
if (sSuffix != null) return (sSuffix.toLowerCase().equals("prs"));
else return false;
}
public String getDescription() { return "Persistance Files (*.prs)"; }
});
jfcChooser.setFileSelectionMode (javax.swing.JFileChooser.FILES_ONLY);
jfcChooser.setMultiSelectionEnabled (false);
return jfcChooser;
}
protected OutputStream retrievePersistanceOutStream() throws IOException, CancelledException {
javax.swing.JFileChooser jfcChooser = getChooser();
File fFile = null;
do {
if (jfcChooser.showSaveDialog (null) == JFileChooser.CANCEL_OPTION)
throw new CancelledException ("File choosing cancelled.");
fFile = jfcChooser.getSelectedFile();
if (fFile == null)
throw new CancelledException ("No file selected.");
if (!jfcChooser.getFileFilter().accept(fFile) && !fFile.exists()) fFile = new File (fFile.getParent(), fFile.getName() + ".prs");
if ((jfcChooser.accept (fFile)) &&
(!fFile.exists())) {
switch (JOptionPane.showConfirmDialog (null,
fFile.getAbsolutePath() + " does not exist.\nCreate?",
"Confirmation",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE)) {
case JOptionPane.NO_OPTION:
fFile = null;
break;
case JOptionPane.CANCEL_OPTION:
throw new CancelledException ("File choosing cancelled.");
case JOptionPane.YES_OPTION:
fFile.createNewFile();
}
}
} while (!jfcChooser.getFileFilter().accept(fFile) || fFile.isDirectory());
return new java.io.FileOutputStream (fFile);
}
protected InputStream retrievePersistanceInStream() throws IOException, CancelledException {
javax.swing.JFileChooser jfcChooser = getChooser();
do {
jfcChooser.getSelectedFile();
if (jfcChooser.showOpenDialog (null) == javax.swing.JFileChooser.CANCEL_OPTION)
throw new CancelledException ("File choosing cancelled.");
} while (!jfcChooser.getSelectedFile().exists());
return new java.io.FileInputStream (jfcChooser.getSelectedFile());
}
public Object setObjectPersistent (Object oKey, Object oToPersistify) {
synchronized (getPersistifyLock()) {
Object oReturn = m_mpToPersistify.remove (oKey);
m_mpToPersistify.put (oKey, oToPersistify);
return oReturn;
}
}
public Object setObjectTransient (Object oKey) {
synchronized (getPersistifyLock()) {
return m_mpToPersistify.remove (oKey);
}
}
public Object getPersistentObject (Object oKey) {
synchronized (getPersistifyLock()) {
return m_mpToPersistify.get (oKey);
}
}
public Iterator getPersistentObjects() {
synchronized (getPersistifyLock()) {
return m_mpToPersistify.values().iterator();
}
}
protected void clearInternalStructures() {
synchronized (getSalesPointsLock()) {
while (m_lspSalesPoints.size() > 0) {
removeSalesPoint ((SalesPoint) m_lspSalesPoints.get (0));
}
}
synchronized (getProcessesLock()) {
m_lphProcesses.clear();
}
if (m_jfShopFrame != null) {
m_jfShopFrame.setVisible (false);
m_jfShopFrame.dispose();
m_jfShopFrame = null;
}
}
public void setShopFrameTitle (String sTitle) {
m_sShopFrameTitle = sTitle;
getShopFrame().setTitle (sTitle);
}
protected JFrame getShopFrame() {
if (m_jfShopFrame == null) {
MultiWindow mw = new MultiWindow (m_sShopFrameTitle, MultiWindow.TABBED);
m_msMultiWindowMenu = mw.getMultiWindowMenuSheet();
MenuSheet ms = createShopMenuSheet();
m_msMultiWindowMenu = null;
mw.setMenuSheet (ms);
mw.setDefaultCloseOperation (JFrame.DO_NOTHING_ON_CLOSE);
mw.addWindowListener (new WindowAdapter() {
public void windowClosing (WindowEvent e) {
new Thread ("Shop closer") {
public void run() {
Shop.getTheShop().quit();
}
}.start();
}
});
m_jfShopFrame = mw;
}
return m_jfShopFrame;
}
protected MenuSheet createShopMenuSheet() {
MenuSheet ms = new MenuSheet ("Shop Menu");
MenuSheet ms2 = new MenuSheet ("Shop", SHOP_MENU_TAG, 'S');
ms2.add (new MenuSheet ("Set current SalesPoint", SET_CURRENT_SP_TAG));
ms2.add (new MenuSheetSeparator (SEPARATOR_ONE_TAG));
MenuSheetItem msi1 = new MenuSheetItem ("Load...", LOAD_TAG, new Action() {
public void doAction (SaleProcess p, SalesPoint sp) throws Throwable {
try {
Shop.getTheShop().restore();
}
catch (CancelledException cexc) {
JOptionPane.showMessageDialog(null, cexc.getMessage(), "Loading cancelled", JOptionPane.ERROR_MESSAGE);
}
}
});
msi1.setAccelerator (KeyStroke.getKeyStroke (KeyEvent.VK_O, InputEvent.CTRL_MASK));
msi1.setMnemonic ('L');
ms2.add (msi1);
MenuSheetItem msi2 = new MenuSheetItem ("Save...", SAVE_TAG, new Action() {
public void doAction (SaleProcess p, SalesPoint sp) throws Throwable {
try{
Shop.getTheShop().makePersistent();
}
catch (CancelledException cexc) {
JOptionPane.showMessageDialog(null, cexc.getMessage(), "Saving cancelled", JOptionPane.ERROR_MESSAGE);
}
}
});
msi2.setAccelerator (KeyStroke.getKeyStroke (KeyEvent.VK_S, InputEvent.CTRL_MASK));
msi2.setMnemonic ('S');
ms2.add (msi2);
ms2.add (new MenuSheetSeparator (SEPARATOR_TWO_TAG));
MenuSheetItem msi3 = new MenuSheetItem ("Quit", QUIT_SHOP_TAG, new Action() {
public void doAction (SaleProcess p, SalesPoint sp) {
Shop.getTheShop().quit();
}
});
msi3.setMnemonic ('Q');
ms2.add (msi3);
ms.add (ms2);
if (m_msMultiWindowMenu != null) {
ms.add (m_msMultiWindowMenu);
}
return ms;
}
public Timer getTimer () {
if (m_trTimer == null) m_trTimer = new StepTimer();
return m_trTimer;
}
public void setTimer (Timer trTimer) {
m_trTimer = trTimer;
}
public void log (Loggable la) throws IOException {
Log.getGlobalLog().log (la);
}
public void addStock (Stock st)
throws DuplicateKeyException {
synchronized (getStocksLock()) {
if (m_mpStocks.containsKey (st.getName())) {
throw new DuplicateKeyException (st.getName());
}
m_mpStocks.put (st.getName(), st);
st.attach (m_ncStockContext);
}
}
public Stock removeStock (String sName) {
synchronized (getStocksLock()) {
Stock st = (Stock) m_mpStocks.remove (sName);
if (st != null) {
st.detachNC();
}
return st;
}
}
public Stock getStock (String sName) {
synchronized (getStocksLock()) {
return (Stock) m_mpStocks.get (sName);
}
}
public void addCatalog (Catalog c)
throws DuplicateKeyException {
synchronized (getCatalogsLock()) {
if (m_mpCatalogs.containsKey (c.getName())) {
throw new DuplicateKeyException (c.getName());
}
m_mpCatalogs.put (c.getName(), c);
c.attach (m_ncCatalogContext);
}
}
public Catalog removeCatalog (String sName) {
synchronized (getCatalogsLock()) {
Catalog c = (Catalog) m_mpCatalogs.remove (sName);
if (c != null) {
c.detachNC();
}
return c;
}
}
public Catalog getCatalog (String sName) {
synchronized (getCatalogsLock()) {
return (Catalog) m_mpCatalogs.get (sName);
}
}
public final static int DEAD = 0;
public final static int RUNNING = 1;
public final static int SUSPENDED = 2;
public static final String SHOP_MENU_TAG = "__TAG:_SHOP_MENU_";
public static final String SET_CURRENT_SP_TAG = "__TAG:_SHOP_SET_CURRENT_SALESPOINT_";
public static final String SEPARATOR_ONE_TAG = "__TAG:_SHOP_SEPARATOR_1_";
public static final String LOAD_TAG = "__TAG:_SHOP_LOAD_";
public static final String SAVE_TAG = "__TAG:_SHOP_SAVE_";
public static final String SEPARATOR_TWO_TAG = "__TAG:_SHOP_SEPARATOR_2_";
public static final String QUIT_SHOP_TAG = "__TAG:_SHOP_QUIT_";
private static Shop s_shTheShop;
private static Object s_oShopLock = new Object();
public static Shop getTheShop() {
synchronized (s_oShopLock) {
if (s_shTheShop == null) {
setTheShop (new Shop());
}
return s_shTheShop;
}
}
public static void setTheShop (Shop shTheShop) {
synchronized (s_oShopLock) {
s_shTheShop = shTheShop;
}
}
}